2 * @license r.js 1.0.7+ Fri, 30 Mar 2012 00:24:35 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
3 * Available via the MIT or new BSD license.
4 * see: http://github.com/jrburke/requirejs for details
8 * This is a bootstrap script to allow running RequireJS in the command line
9 * in either a Java/Rhino or Node environment. It is modified by the top-level
10 * dist.js file to inject other files to completely enable this file. It is
11 * the shell of the r.js file.
14 /*jslint evil: true, nomen: true */
15 /*global readFile: true, process: false, Packages: false, print: false,
16 console: false, java: false, module: false, requirejsVars */
18 var requirejs, require, define;
19 (function (console, args, readFileFunc) {
21 var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire,
22 nodeDefine, exists, reqMain, loadedOptimizedLib,
23 version = '1.0.7+ Fri, 30 Mar 2012 00:24:35 GMT',
24 jsSuffixRegExp = /\.js$/,
27 //Used by jslib/rhino/args.js
29 readFile = typeof readFileFunc !== 'undefined' ? readFileFunc : null;
32 console.log('See https://github.com/jrburke/r.js for usage.');
35 if (typeof Packages !== 'undefined') {
40 if (fileName && fileName.indexOf('-') === 0) {
41 commandOption = fileName.substring(1);
45 //Set up execution context.
46 rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext();
48 exec = function (string, name) {
49 return rhinoContext.evaluateString(this, string, name, 0, null);
52 exists = function (fileName) {
53 return (new java.io.File(fileName)).exists();
56 //Define a console.log for easier logging. Don't
58 if (typeof console === 'undefined') {
61 print.apply(undefined, arguments);
65 } else if (typeof process !== 'undefined') {
68 //Get the fs module via Node's require before it
69 //gets replaced. Used in require/node.js
72 path = require('path');
73 nodeRequire = require;
75 reqMain = require.main;
77 //Temporarily hide require and define to allow require.js to define
82 readFile = function (path) {
83 return fs.readFileSync(path, 'utf8');
86 exec = function (string, name) {
87 return vm.runInThisContext(this.requirejsVars.require.makeNodeWrapper(string),
88 name ? fs.realpathSync(name) : '');
91 exists = function (fileName) {
92 return path.existsSync(fileName);
96 fileName = process.argv[2];
98 if (fileName && fileName.indexOf('-') === 0) {
99 commandOption = fileName.substring(1);
100 fileName = process.argv[3];
104 /** vim: et:ts=4:sw=4:sts=4
105 * @license RequireJS 1.0.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
106 * Available via the MIT or new BSD license.
107 * see: http://github.com/jrburke/requirejs for details
109 /*jslint strict: false, plusplus: false, sub: true */
110 /*global window, navigator, document, importScripts, jQuery, setTimeout, opera */
114 //Change this version number for each release.
115 var version = "1.0.7",
116 commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
117 cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g,
118 currDirRegExp = /^\.\//,
119 jsSuffixRegExp = /\.js$/,
120 ostring = Object.prototype.toString,
121 ap = Array.prototype,
124 isBrowser = !!(typeof window !== "undefined" && navigator && document),
125 isWebWorker = !isBrowser && typeof importScripts !== "undefined",
126 //PS3 indicates loaded and complete, but need to wait for complete
127 //specifically. Sequence is "loading", "loaded", execution,
128 // then "complete". The UA check is unfortunate, but not sure how
129 //to feature test w/o causing perf issues.
130 readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
131 /^complete$/ : /^(complete|loaded)$/,
132 defContextName = "_",
133 //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
134 isOpera = typeof opera !== "undefined" && opera.toString() === "[object Opera]",
138 interactiveScript = null,
139 checkLoadedDepth = 0,
140 useInteractive = false,
141 reservedDependencies = {
146 req, cfg = {}, currentlyAddingScript, s, head, baseElement, scripts, script,
147 src, subPath, mainScript, dataMain, globalI, ctx, jQueryCheck, checkLoadedTimeoutId;
149 function isFunction(it) {
150 return ostring.call(it) === "[object Function]";
153 function isArray(it) {
154 return ostring.call(it) === "[object Array]";
158 * Simple function to mix in properties from source into target,
159 * but only if target does not already have a property of the same name.
160 * This is not robust in IE for transferring methods that match
161 * Object.prototype names, but the uses of mixin here seem unlikely to
162 * trigger a problem related to that.
164 function mixin(target, source, force) {
165 for (var prop in source) {
166 if (!(prop in empty) && (!(prop in target) || force)) {
167 target[prop] = source[prop];
174 * Constructs an error with a pointer to an URL with more information.
175 * @param {String} id the error ID that maps to an ID on a web page.
176 * @param {String} message human readable error.
177 * @param {Error} [err] the original error, if there is one.
181 function makeError(id, msg, err) {
182 var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
184 e.originalError = err;
190 * Used to set up package paths from a packagePaths or packages config object.
191 * @param {Object} pkgs the object to store the new package config
192 * @param {Array} currentPackages an array of packages to configure
193 * @param {String} [dir] a prefix dir to use.
195 function configurePackageDir(pkgs, currentPackages, dir) {
196 var i, location, pkgObj;
198 for (i = 0; (pkgObj = currentPackages[i]); i++) {
199 pkgObj = typeof pkgObj === "string" ? { name: pkgObj } : pkgObj;
200 location = pkgObj.location;
202 //Add dir to the path, but avoid paths that start with a slash
203 //or have a colon (indicates a protocol)
204 if (dir && (!location || (location.indexOf("/") !== 0 && location.indexOf(":") === -1))) {
205 location = dir + "/" + (location || pkgObj.name);
208 //Create a brand new object on pkgs, since currentPackages can
209 //be passed in again, and config.pkgs is the internal transformed
210 //state for all package configs.
211 pkgs[pkgObj.name] = {
213 location: location || pkgObj.name,
214 //Remove leading dot in main, so main paths are normalized,
215 //and remove any trailing .js, since different package
216 //envs have different conventions: some use a module name,
217 //some use a file name.
218 main: (pkgObj.main || "main")
219 .replace(currDirRegExp, '')
220 .replace(jsSuffixRegExp, '')
226 * jQuery 1.4.3-1.5.x use a readyWait/ready() pairing to hold DOM
227 * ready callbacks, but jQuery 1.6 supports a holdReady() API instead.
228 * At some point remove the readyWait/ready() support and just stick
229 * with using holdReady.
231 function jQueryHoldReady($, shouldHold) {
233 $.holdReady(shouldHold);
234 } else if (shouldHold) {
241 if (typeof define !== "undefined") {
242 //If a define is already in play via another AMD loader,
247 if (typeof requirejs !== "undefined") {
248 if (isFunction(requirejs)) {
249 //Do not overwrite and existing requirejs instance.
253 requirejs = undefined;
257 //Allow for a require config object
258 if (typeof require !== "undefined" && !isFunction(require)) {
259 //assume it is a config object.
265 * Creates a new context for use in require and define calls.
266 * Handle most of the heavy lifting. Do not want to use an object
267 * with prototype here to avoid using "this" in require, in case it
268 * needs to be used in more super secure envs that do not want this.
269 * Also there should not be that many contexts in the page. Usually just
270 * one for the default context, but could be extra for multiversion cases
271 * or if a package needs a special context for a dependency that conflicts
272 * with the standard context.
274 function newContext(contextName) {
296 managerCallbacks = {},
298 //Used to indicate which modules in a build scenario
299 //need to be full executed.
305 * Trims the . and .. from an array of path segments.
306 * It will keep a leading path segment if a .. will become
307 * the first path segment, to help with module name lookups,
308 * which act like paths, but can be remapped. But the end result,
309 * all paths that use this function should look normalized.
310 * NOTE: this method MODIFIES the input array.
311 * @param {Array} ary the array of path segments.
313 function trimDots(ary) {
315 for (i = 0; (part = ary[i]); i++) {
319 } else if (part === "..") {
320 if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
321 //End of the line. Keep at least one non-dot
322 //path segment at the front so it can be mapped
323 //correctly to disk. Otherwise, there is likely
324 //no path mapping for a path starting with '..'.
325 //This can still fail, but catches the most reasonable
329 ary.splice(i - 1, 2);
337 * Given a relative module name, like ./something, normalize it to
338 * a real name that can be mapped to a path.
339 * @param {String} name the relative name
340 * @param {String} baseName a real name that the name arg is relative
342 * @returns {String} normalized name
344 function normalize(name, baseName) {
345 var pkgName, pkgConfig;
347 //Adjust any relative paths.
348 if (name && name.charAt(0) === ".") {
349 //If have a base name, try to normalize against it,
350 //otherwise, assume it is a top-level require that will
351 //be relative to baseUrl in the end.
353 if (config.pkgs[baseName]) {
354 //If the baseName is a package name, then just treat it as one
355 //name to concat the name with.
356 baseName = [baseName];
358 //Convert baseName to array, and lop off the last part,
359 //so that . matches that "directory" and not name of the baseName's
360 //module. For instance, baseName of "one/two/three", maps to
361 //"one/two/three.js", but we want the directory, "one/two" for
362 //this normalization.
363 baseName = baseName.split("/");
364 baseName = baseName.slice(0, baseName.length - 1);
367 name = baseName.concat(name.split("/"));
370 //Some use of packages may use a . path to reference the
371 //"main" module name, so normalize for that.
372 pkgConfig = config.pkgs[(pkgName = name[0])];
373 name = name.join("/");
374 if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
377 } else if (name.indexOf("./") === 0) {
378 // No baseName, so this is ID is resolved relative
379 // to baseUrl, pull off the leading dot.
380 name = name.substring(2);
387 * Creates a module mapping that includes plugin prefix, module
388 * name, and path. If parentModuleMap is provided it will
389 * also normalize the name via require.normalize()
391 * @param {String} name the module name
392 * @param {String} [parentModuleMap] parent module map
393 * for the module name, used to resolve relative names.
397 function makeModuleMap(name, parentModuleMap) {
398 var index = name ? name.indexOf("!") : -1,
400 parentName = parentModuleMap ? parentModuleMap.name : null,
402 normalizedName, url, pluginModule;
405 prefix = name.substring(0, index);
406 name = name.substring(index + 1, name.length);
410 prefix = normalize(prefix, parentName);
413 //Account for relative paths if there is a base name.
416 pluginModule = defined[prefix];
417 if (pluginModule && pluginModule.normalize) {
418 //Plugin is loaded, use its normalize method.
419 normalizedName = pluginModule.normalize(name, function (name) {
420 return normalize(name, parentName);
423 normalizedName = normalize(name, parentName);
427 normalizedName = normalize(name, parentName);
429 url = urlMap[normalizedName];
431 //Calculate url for the module, if it has a name.
432 //Use name here since nameToUrl also calls normalize,
433 //and for relative names that are outside the baseUrl
434 //this causes havoc. Was thinking of just removing
435 //parentModuleMap to avoid extra normalization, but
436 //normalize() still does a dot removal because of
437 //issue #142, so just pass in name here and redo
438 //the normalization. Paths outside baseUrl are just
440 url = context.nameToUrl(name, null, parentModuleMap);
442 //Store the URL mapping for later.
443 urlMap[normalizedName] = url;
450 name: normalizedName,
451 parentMap: parentModuleMap,
453 originalName: originalName,
454 fullName: prefix ? prefix + "!" + (normalizedName || '') : normalizedName
459 * Determine if priority loading is done. If so clear the priorityWait
461 function isPriorityDone() {
462 var priorityDone = true,
463 priorityWait = config.priorityWait,
466 for (i = 0; (priorityName = priorityWait[i]); i++) {
467 if (!loaded[priorityName]) {
468 priorityDone = false;
473 delete config.priorityWait;
479 function makeContextModuleFunc(func, relModuleMap, enableBuildCallback) {
481 //A version of a require function that passes a moduleName
482 //value for items that may need to
483 //look up paths relative to the moduleName
484 var args = aps.call(arguments, 0), lastArg;
485 if (enableBuildCallback &&
486 isFunction((lastArg = args[args.length - 1]))) {
487 lastArg.__requireJsBuild = true;
489 args.push(relModuleMap);
490 return func.apply(null, args);
495 * Helper function that creates a require function object to give to
496 * modules that ask for it as a dependency. It needs to be specific
497 * per module because of the implication of path mappings that may
498 * need to be relative to the module name.
500 function makeRequire(relModuleMap, enableBuildCallback, altRequire) {
501 var modRequire = makeContextModuleFunc(altRequire || context.require, relModuleMap, enableBuildCallback);
504 nameToUrl: makeContextModuleFunc(context.nameToUrl, relModuleMap),
505 toUrl: makeContextModuleFunc(context.toUrl, relModuleMap),
506 defined: makeContextModuleFunc(context.requireDefined, relModuleMap),
507 specified: makeContextModuleFunc(context.requireSpecified, relModuleMap),
508 isBrowser: req.isBrowser
514 * Queues a dependency for checking after the loader is out of a
515 * "paused" state, for example while a script file is being loaded
516 * in the browser, where it may have many modules defined in it.
518 function queueDependency(manager) {
519 context.paused.push(manager);
522 function execManager(manager) {
523 var i, ret, err, errFile, errModuleTree,
524 cb = manager.callback,
526 fullName = map.fullName,
528 listeners = manager.listeners,
529 execCb = config.requireExecCb || req.execCb,
532 //Call the callback to define the module, if necessary.
533 if (cb && isFunction(cb)) {
534 if (config.catchError.define) {
536 ret = execCb(fullName, manager.callback, args, defined[fullName]);
541 ret = execCb(fullName, manager.callback, args, defined[fullName]);
545 //If setting exports via "module" is in play,
546 //favor that over return value and exports. After that,
547 //favor a non-undefined return value over exports use.
548 cjsModule = manager.cjsModule;
550 cjsModule.exports !== undefined &&
551 //Make sure it is not already the exports value
552 cjsModule.exports !== defined[fullName]) {
553 ret = defined[fullName] = manager.cjsModule.exports;
554 } else if (ret === undefined && manager.usingExports) {
555 //exports already set the defined value.
556 ret = defined[fullName];
558 //Use the return value from the function.
559 defined[fullName] = ret;
560 //If this module needed full execution in a build
561 //environment, mark that now.
562 if (needFullExec[fullName]) {
563 fullExec[fullName] = true;
567 } else if (fullName) {
568 //May just be an object definition for the module. Only
569 //worry about defining if have a module name.
570 ret = defined[fullName] = cb;
572 //If this module needed full execution in a build
573 //environment, mark that now.
574 if (needFullExec[fullName]) {
575 fullExec[fullName] = true;
579 //Clean up waiting. Do this before error calls, and before
580 //calling back listeners, so that bookkeeping is correct
581 //in the event of an error and error is reported in correct order,
582 //since the listeners will likely have errors if the
583 //onError function does not throw.
584 if (waiting[manager.id]) {
585 delete waiting[manager.id];
586 manager.isDone = true;
587 context.waitCount -= 1;
588 if (context.waitCount === 0) {
589 //Clear the wait array used for cycles.
594 //Do not need to track manager callback now that it is defined.
595 delete managerCallbacks[fullName];
597 //Allow instrumentation like the optimizer to know the order
598 //of modules executed and their dependencies.
599 if (req.onResourceLoad && !manager.placeholder) {
600 req.onResourceLoad(context, map, manager.depArray);
604 errFile = (fullName ? makeModuleMap(fullName).url : '') ||
605 err.fileName || err.sourceURL;
606 errModuleTree = err.moduleTree;
607 err = makeError('defineerror', 'Error evaluating ' +
608 'module "' + fullName + '" at location "' +
610 err + '\nfileName:' + errFile +
611 '\nlineNumber: ' + (err.lineNumber || err.line), err);
612 err.moduleName = fullName;
613 err.moduleTree = errModuleTree;
614 return req.onError(err);
617 //Let listeners know of this manager's value.
618 for (i = 0; (cb = listeners[i]); i++) {
626 * Helper that creates a callack function that is called when a dependency
627 * is ready, and sets the i-th dependency for the manager as the
628 * value passed to the callback generated by this function.
630 function makeArgCallback(manager, i) {
631 return function (value) {
632 //Only do the work if it has not been done
633 //already for a dependency. Cycle breaking
634 //logic in forceExec could mean this function
635 //is called more than once for a given dependency.
636 if (!manager.depDone[i]) {
637 manager.depDone[i] = true;
638 manager.deps[i] = value;
639 manager.depCount -= 1;
640 if (!manager.depCount) {
642 execManager(manager);
648 function callPlugin(pluginName, depManager) {
649 var map = depManager.map,
650 fullName = map.fullName,
652 plugin = plugins[pluginName] ||
653 (plugins[pluginName] = defined[pluginName]),
656 //No need to continue if the manager is already
657 //in the process of loading.
658 if (depManager.loading) {
661 depManager.loading = true;
663 load = function (ret) {
664 depManager.callback = function () {
667 execManager(depManager);
669 loaded[depManager.id] = true;
671 //The loading of this plugin
672 //might have placed other things
673 //in the paused queue. In particular,
674 //a loader plugin that depends on
675 //a different plugin loaded resource.
679 //Allow plugins to load other code without having to know the
680 //context or how to "complete" the load.
681 load.fromText = function (moduleName, text) {
682 /*jslint evil: true */
683 var hasInteractive = useInteractive;
685 //Indicate a the module is in process of loading.
686 loaded[moduleName] = false;
687 context.scriptCount += 1;
689 //Indicate this is not a "real" module, so do not track it
690 //for builds, it does not map to a real file.
691 context.fake[moduleName] = true;
693 //Turn off interactive script matching for IE for any define
694 //calls in the text, then turn it back on at the end.
695 if (hasInteractive) {
696 useInteractive = false;
701 if (hasInteractive) {
702 useInteractive = true;
705 //Support anonymous modules.
706 context.completeLoad(moduleName);
709 //No need to continue if the plugin value has already been
710 //defined by a build.
711 if (fullName in defined) {
712 load(defined[fullName]);
714 //Use parentName here since the plugin's name is not reliable,
715 //could be some weird string with no path that actually wants to
716 //reference the parentName's path.
717 plugin.load(name, makeRequire(map.parentMap, true, function (deps, cb) {
720 //Convert deps to full names and hold on to them
721 //for reference later, when figuring out if they
722 //are blocked by a circular dependency.
723 for (i = 0; (dep = deps[i]); i++) {
724 depMap = makeModuleMap(dep, map.parentMap);
725 deps[i] = depMap.fullName;
726 if (!depMap.prefix) {
727 moduleDeps.push(deps[i]);
730 depManager.moduleDeps = (depManager.moduleDeps || []).concat(moduleDeps);
731 return context.require(deps, cb);
737 * Adds the manager to the waiting queue. Only fully
738 * resolved items should be in the waiting queue.
740 function addWait(manager) {
741 if (!waiting[manager.id]) {
742 waiting[manager.id] = manager;
743 waitAry.push(manager);
744 context.waitCount += 1;
749 * Function added to every manager object. Created out here
750 * to avoid new function creation for each manager instance.
752 function managerAdd(cb) {
753 this.listeners.push(cb);
756 function getManager(map, shouldQueue) {
757 var fullName = map.fullName,
759 plugin = prefix ? plugins[prefix] ||
760 (plugins[prefix] = defined[prefix]) : null,
761 manager, created, pluginManager, prefixMap;
764 manager = managerCallbacks[fullName];
770 //ID is just the full name, but if it is a plugin resource
771 //for a plugin that has not been loaded,
772 //then add an ID counter to it.
773 id: (prefix && !plugin ?
774 (managerCounter++) + '__p@:' : '') +
775 (fullName || '__r@' + (managerCounter++)),
785 specified[manager.id] = true;
787 //Only track the manager/reuse it if this is a non-plugin
788 //resource. Also only track plugin resources once
789 //the plugin has been loaded, and so the fullName is the
790 //true normalized value.
791 if (fullName && (!prefix || plugins[prefix])) {
792 managerCallbacks[fullName] = manager;
796 //If there is a plugin needed, but it is not loaded,
797 //first load the plugin, then continue on.
798 if (prefix && !plugin) {
799 prefixMap = makeModuleMap(prefix);
801 //Clear out defined and urlFetched if the plugin was previously
802 //loaded/defined, but not as full module (as in a build
803 //situation). However, only do this work if the plugin is in
804 //defined but does not have a module export value.
805 if (prefix in defined && !defined[prefix]) {
806 delete defined[prefix];
807 delete urlFetched[prefixMap.url];
810 pluginManager = getManager(prefixMap, true);
811 pluginManager.add(function (plugin) {
812 //Create a new manager for the normalized
813 //resource ID and have it call this manager when
815 var newMap = makeModuleMap(map.originalName, map.parentMap),
816 normalizedManager = getManager(newMap, true);
818 //Indicate this manager is a placeholder for the real,
819 //normalized thing. Important for when trying to map
820 //modules and dependencies, for instance, in a build.
821 manager.placeholder = true;
823 normalizedManager.add(function (resource) {
824 manager.callback = function () {
827 execManager(manager);
830 } else if (created && shouldQueue) {
831 //Indicate the resource is not loaded yet if it is to be
833 loaded[manager.id] = false;
834 queueDependency(manager);
841 function main(inName, depArray, callback, relModuleMap) {
842 var moduleMap = makeModuleMap(inName, relModuleMap),
843 name = moduleMap.name,
844 fullName = moduleMap.fullName,
845 manager = getManager(moduleMap),
848 i, depArg, depName, depPrefix, cjsMod;
851 //If module already defined for context, or already loaded,
852 //then leave. Also leave if jQuery is registering but it does
853 //not match the desired version number in the config.
854 if (fullName in defined || loaded[id] === true ||
855 (fullName === "jquery" && config.jQuery &&
856 config.jQuery !== callback().fn.jquery)) {
860 //Set specified/loaded here for modules that are also loaded
861 //as part of a layer, where onScriptLoad is not fired
862 //for those cases. Do this after the inline define and
863 //dependency tracing is done.
864 specified[id] = true;
867 //If module is jQuery set up delaying its dom ready listeners.
868 if (fullName === "jquery" && callback) {
869 jQueryCheck(callback());
873 //Attach real depArray and callback to the manager. Do this
874 //only if the module has not been defined already, so do this after
875 //the fullName checks above. IE can call main() more than once
877 manager.depArray = depArray;
878 manager.callback = callback;
880 //Add the dependencies to the deps field, and register for callbacks
881 //on the dependencies.
882 for (i = 0; i < depArray.length; i++) {
883 depArg = depArray[i];
884 //There could be cases like in IE, where a trailing comma will
885 //introduce a null dependency, so only treat a real dependency
886 //value as a dependency.
888 //Split the dependency name into plugin and name parts
889 depArg = makeModuleMap(depArg, (name ? moduleMap : relModuleMap));
890 depName = depArg.fullName;
891 depPrefix = depArg.prefix;
893 //Fix the name in depArray to be just the name, since
894 //that is how it will be called back later.
895 depArray[i] = depName;
897 //Fast path CommonJS standard dependencies.
898 if (depName === "require") {
899 deps[i] = makeRequire(moduleMap);
900 } else if (depName === "exports") {
901 //CommonJS module spec 1.1
902 deps[i] = defined[fullName] = {};
903 manager.usingExports = true;
904 } else if (depName === "module") {
905 //CommonJS module spec 1.1
906 manager.cjsModule = cjsMod = deps[i] = {
908 uri: name ? context.nameToUrl(name, null, relModuleMap) : undefined,
909 exports: defined[fullName]
911 } else if (depName in defined && !(depName in waiting) &&
912 (!(fullName in needFullExec) ||
913 (fullName in needFullExec && fullExec[depName]))) {
914 //Module already defined, and not in a build situation
915 //where the module is a something that needs full
916 //execution and this dependency has not been fully
917 //executed. See r.js's requirePatch.js for more info
919 deps[i] = defined[depName];
921 //Mark this dependency as needing full exec if
922 //the current module needs full exec.
923 if (fullName in needFullExec) {
924 needFullExec[depName] = true;
925 //Reset state so fully executed code will get
926 //picked up correctly.
927 delete defined[depName];
928 urlFetched[depArg.url] = false;
931 //Either a resource that is not loaded yet, or a plugin
932 //resource for either a plugin that has not
934 manager.depCount += 1;
935 manager.depCallbacks[i] = makeArgCallback(manager, i);
936 getManager(depArg, true).add(manager.depCallbacks[i]);
941 //Do not bother tracking the manager if it is all done.
942 if (!manager.depCount) {
944 execManager(manager);
951 * Convenience method to call main for a define call that was put on
952 * hold in the defQueue.
954 function callDefMain(args) {
955 main.apply(null, args);
959 * jQuery 1.4.3+ supports ways to hold off calling
960 * calling jQuery ready callbacks until all scripts are loaded. Be sure
961 * to track it if the capability exists.. Also, since jQuery 1.4.3 does
962 * not register as a module, need to do some global inference checking.
963 * Even if it does register as a module, not guaranteed to be the precise
964 * name of the global. If a jQuery is tracked for this context, then go
965 * ahead and register it as a module too, if not already in process.
967 jQueryCheck = function (jqCandidate) {
968 if (!context.jQuery) {
969 var $ = jqCandidate || (typeof jQuery !== "undefined" ? jQuery : null);
972 //If a specific version of jQuery is wanted, make sure to only
973 //use this jQuery if it matches.
974 if (config.jQuery && $.fn.jquery !== config.jQuery) {
978 if ("holdReady" in $ || "readyWait" in $) {
981 //Manually create a "jquery" module entry if not one already
982 //or in process. Note this could trigger an attempt at
983 //a second jQuery registration, but does no harm since
984 //the first one wins, and it is the same value anyway.
985 callDefMain(["jquery", [], function () {
989 //Ask jQuery to hold DOM ready callbacks.
990 if (context.scriptCount) {
991 jQueryHoldReady($, true);
992 context.jQueryIncremented = true;
999 function findCycle(manager, traced) {
1000 var fullName = manager.map.fullName,
1001 depArray = manager.depArray,
1003 i, depName, depManager, result;
1005 if (manager.isDone || !fullName || !loaded[fullName]) {
1010 if (traced[fullName]) {
1014 traced[fullName] = true;
1016 //Trace through the dependencies.
1018 for (i = 0; i < depArray.length; i++) {
1019 //Some array members may be null, like if a trailing comma
1020 //IE, so do the explicit [i] access and check if it has a value.
1021 depName = depArray[i];
1022 if (!loaded[depName] && !reservedDependencies[depName]) {
1023 fullyLoaded = false;
1026 depManager = waiting[depName];
1027 if (depManager && !depManager.isDone && loaded[depName]) {
1028 result = findCycle(depManager, traced);
1035 //Discard the cycle that was found, since it cannot
1036 //be forced yet. Also clear this module from traced.
1038 delete traced[fullName];
1045 function forceExec(manager, traced) {
1046 var fullName = manager.map.fullName,
1047 depArray = manager.depArray,
1048 i, depName, depManager, prefix, prefixManager, value;
1051 if (manager.isDone || !fullName || !loaded[fullName]) {
1056 if (traced[fullName]) {
1057 return defined[fullName];
1060 traced[fullName] = true;
1063 //Trace through the dependencies.
1065 for (i = 0; i < depArray.length; i++) {
1066 //Some array members may be null, like if a trailing comma
1067 //IE, so do the explicit [i] access and check if it has a value.
1068 depName = depArray[i];
1070 //First, make sure if it is a plugin resource that the
1071 //plugin is not blocked.
1072 prefix = makeModuleMap(depName).prefix;
1073 if (prefix && (prefixManager = waiting[prefix])) {
1074 forceExec(prefixManager, traced);
1076 depManager = waiting[depName];
1077 if (depManager && !depManager.isDone && loaded[depName]) {
1078 value = forceExec(depManager, traced);
1079 manager.depCallbacks[i](value);
1085 return defined[fullName];
1089 * Checks if all modules for a context are loaded, and if so, evaluates the
1090 * new ones in right dependency order.
1094 function checkLoaded() {
1095 var waitInterval = config.waitSeconds * 1000,
1096 //It is possible to disable the wait interval by using waitSeconds of 0.
1097 expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
1098 noLoads = "", hasLoadedProp = false, stillLoading = false,
1100 i, prop, err, manager, cycleManager, moduleDeps;
1102 //If there are items still in the paused queue processing wait.
1103 //This is particularly important in the sync case where each paused
1104 //item is processed right away but there may be more waiting.
1105 if (context.pausedCount > 0) {
1109 //Determine if priority loading is done. If so clear the priority. If
1110 //not, then do not check
1111 if (config.priorityWait) {
1112 if (isPriorityDone()) {
1113 //Call resume, since it could have
1114 //some waiting dependencies to trace.
1121 //See if anything is still in flight.
1122 for (prop in loaded) {
1123 if (!(prop in empty)) {
1124 hasLoadedProp = true;
1125 if (!loaded[prop]) {
1127 noLoads += prop + " ";
1129 stillLoading = true;
1130 if (prop.indexOf('!') === -1) {
1131 //No reason to keep looking for unfinished
1132 //loading. If the only stillLoading is a
1133 //plugin resource though, keep going,
1134 //because it may be that a plugin resource
1135 //is waiting on a non-plugin cycle.
1139 moduleDeps = managerCallbacks[prop] && managerCallbacks[prop].moduleDeps;
1141 cycleDeps.push.apply(cycleDeps, moduleDeps);
1149 //Check for exit conditions.
1150 if (!hasLoadedProp && !context.waitCount) {
1151 //If the loaded object had no items, then the rest of
1152 //the work below does not need to be done.
1155 if (expired && noLoads) {
1156 //If wait time expired, throw error of unloaded modules.
1157 err = makeError("timeout", "Load timeout for modules: " + noLoads);
1158 err.requireType = "timeout";
1159 err.requireModules = noLoads;
1160 err.contextName = context.contextName;
1161 return req.onError(err);
1164 //If still loading but a plugin is waiting on a regular module cycle
1166 if (stillLoading && cycleDeps.length) {
1167 for (i = 0; (manager = waiting[cycleDeps[i]]); i++) {
1168 if ((cycleManager = findCycle(manager, {}))) {
1169 forceExec(cycleManager, {});
1176 //If still waiting on loads, and the waiting load is something
1177 //other than a plugin resource, or there are still outstanding
1178 //scripts, then just try back later.
1179 if (!expired && (stillLoading || context.scriptCount)) {
1180 //Something is still waiting to load. Wait for it, but only
1181 //if a timeout is not already in effect.
1182 if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
1183 checkLoadedTimeoutId = setTimeout(function () {
1184 checkLoadedTimeoutId = 0;
1191 //If still have items in the waiting cue, but all modules have
1192 //been loaded, then it means there are some circular dependencies
1193 //that need to be broken.
1194 //However, as a waiting thing is fired, then it can add items to
1195 //the waiting cue, and those items should not be fired yet, so
1196 //make sure to redo the checkLoaded call after breaking a single
1197 //cycle, if nothing else loaded then this logic will pick it up
1199 if (context.waitCount) {
1200 //Cycle through the waitAry, and call items in sequence.
1201 for (i = 0; (manager = waitAry[i]); i++) {
1202 forceExec(manager, {});
1205 //If anything got placed in the paused queue, run it down.
1206 if (context.paused.length) {
1210 //Only allow this recursion to a certain depth. Only
1211 //triggered by errors in calling a module in which its
1212 //modules waiting on it cannot finish loading, or some circular
1213 //dependencies that then may add more dependencies.
1214 //The value of 5 is a bit arbitrary. Hopefully just one extra
1215 //pass, or two for the case of circular dependencies generating
1216 //more work that gets resolved in the sync node case.
1217 if (checkLoadedDepth < 5) {
1218 checkLoadedDepth += 1;
1223 checkLoadedDepth = 0;
1225 //Check for DOM ready, and nothing is waiting across contexts.
1226 req.checkReadyState();
1232 * Resumes tracing of dependencies and then checks if everything is loaded.
1234 resume = function () {
1235 var manager, map, url, i, p, args, fullName;
1237 //Any defined modules in the global queue, intake them now.
1238 context.takeGlobalQueue();
1242 if (context.scriptCount <= 0) {
1243 //Synchronous envs will push the number below zero with the
1244 //decrement above, be sure to set it back to zero for good measure.
1245 //require() calls that also do not end up loading scripts could
1246 //push the number negative too.
1247 context.scriptCount = 0;
1250 //Make sure any remaining defQueue items get properly processed.
1251 while (defQueue.length) {
1252 args = defQueue.shift();
1253 if (args[0] === null) {
1254 return req.onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
1260 //Skip the resume of paused dependencies
1261 //if current context is in priority wait.
1262 if (!config.priorityWait || isPriorityDone()) {
1263 while (context.paused.length) {
1265 context.pausedCount += p.length;
1267 context.paused = [];
1269 for (i = 0; (manager = p[i]); i++) {
1272 fullName = map.fullName;
1274 //If the manager is for a plugin managed resource,
1275 //ask the plugin to load it now.
1277 callPlugin(map.prefix, manager);
1279 //Regular dependency.
1280 if (!urlFetched[url] && !loaded[fullName]) {
1281 (config.requireLoad || req.load)(context, fullName, url);
1283 //Mark the URL as fetched, but only if it is
1284 //not an empty: URL, used by the optimizer.
1285 //In that case we need to be sure to call
1286 //load() for each module that is mapped to
1287 //empty: so that dependencies are satisfied
1289 if (url.indexOf('empty:') !== 0) {
1290 urlFetched[url] = true;
1296 //Move the start time for timeout forward.
1297 context.startTime = (new Date()).getTime();
1298 context.pausedCount -= p.length;
1302 //Only check if loaded when resume depth is 1. It is likely that
1303 //it is only greater than 1 in sync environments where a factory
1304 //function also then calls the callback-style require. In those
1305 //cases, the checkLoaded should not occur until the resume
1306 //depth is back at the top level.
1307 if (resumeDepth === 1) {
1316 //Define the context object. Many of these fields are on here
1317 //just to make debugging easier.
1319 contextName: contextName,
1324 specified: specified,
1327 urlFetched: urlFetched,
1333 needFullExec: needFullExec,
1336 managerCallbacks: managerCallbacks,
1337 makeModuleMap: makeModuleMap,
1338 normalize: normalize,
1340 * Set a configuration for the context.
1341 * @param {Object} cfg config object to integrate.
1343 configure: function (cfg) {
1344 var paths, prop, packages, pkgs, packagePaths, requireWait;
1346 //Make sure the baseUrl ends in a slash.
1348 if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== "/") {
1353 //Save off the paths and packages since they require special processing,
1354 //they are additive.
1355 paths = config.paths;
1356 packages = config.packages;
1359 //Mix in the config values, favoring the new values over
1360 //existing ones in context.config.
1361 mixin(config, cfg, true);
1363 //Adjust paths if necessary.
1365 for (prop in cfg.paths) {
1366 if (!(prop in empty)) {
1367 paths[prop] = cfg.paths[prop];
1370 config.paths = paths;
1373 packagePaths = cfg.packagePaths;
1374 if (packagePaths || cfg.packages) {
1375 //Convert packagePaths into a packages config.
1377 for (prop in packagePaths) {
1378 if (!(prop in empty)) {
1379 configurePackageDir(pkgs, packagePaths[prop], prop);
1384 //Adjust packages if necessary.
1386 configurePackageDir(pkgs, cfg.packages);
1389 //Done with modifications, assing packages back to context config
1393 //If priority loading is in effect, trigger the loads now
1395 //Hold on to requireWait value, and reset it after done
1396 requireWait = context.requireWait;
1398 //Allow tracing some require calls to allow the fetching
1399 //of the priority config.
1400 context.requireWait = false;
1401 //But first, call resume to register any defined modules that may
1402 //be in a data-main built file before the priority config
1406 context.require(cfg.priority);
1408 //Trigger a resume right away, for the case when
1409 //the script with the priority load is done as part
1410 //of a data-main call. In that case the normal resume
1411 //call will not happen because the scriptCount will be
1412 //at 1, since the script for data-main is being processed.
1415 //Restore previous state.
1416 context.requireWait = requireWait;
1417 config.priorityWait = cfg.priority;
1420 //If a deps array or a config callback is specified, then call
1421 //require with those args. This is useful when require is defined as a
1422 //config object before require.js is loaded.
1423 if (cfg.deps || cfg.callback) {
1424 context.require(cfg.deps || [], cfg.callback);
1428 requireDefined: function (moduleName, relModuleMap) {
1429 return makeModuleMap(moduleName, relModuleMap).fullName in defined;
1432 requireSpecified: function (moduleName, relModuleMap) {
1433 return makeModuleMap(moduleName, relModuleMap).fullName in specified;
1436 require: function (deps, callback, relModuleMap) {
1437 var moduleName, fullName, moduleMap;
1438 if (typeof deps === "string") {
1439 if (isFunction(callback)) {
1441 return req.onError(makeError("requireargs", "Invalid require call"));
1444 //Synchronous access to one module. If require.get is
1445 //available (as in the Node adapter), prefer that.
1446 //In this case deps is the moduleName and callback is
1449 return req.get(context, deps, callback);
1452 //Just return the module wanted. In this scenario, the
1453 //second arg (if passed) is just the relModuleMap.
1455 relModuleMap = callback;
1457 //Normalize module name, if it contains . or ..
1458 moduleMap = makeModuleMap(moduleName, relModuleMap);
1459 fullName = moduleMap.fullName;
1461 if (!(fullName in defined)) {
1462 return req.onError(makeError("notloaded", "Module name '" +
1463 moduleMap.fullName +
1464 "' has not been loaded yet for context: " +
1467 return defined[fullName];
1470 //Call main but only if there are dependencies or
1471 //a callback to call.
1472 if (deps && deps.length || callback) {
1473 main(null, deps, callback, relModuleMap);
1476 //If the require call does not trigger anything new to load,
1477 //then resume the dependency processing.
1478 if (!context.requireWait) {
1479 while (!context.scriptCount && context.paused.length) {
1483 return context.require;
1487 * Internal method to transfer globalQueue items to this context's
1490 takeGlobalQueue: function () {
1491 //Push all the globalDefQueue items into the context's defQueue
1492 if (globalDefQueue.length) {
1493 //Array splice in the values since the context code has a
1494 //local var ref to defQueue, so cannot just reassign the one
1496 apsp.apply(context.defQueue,
1497 [context.defQueue.length - 1, 0].concat(globalDefQueue));
1498 globalDefQueue = [];
1503 * Internal method used by environment adapters to complete a load event.
1504 * A load event could be a script load or just a load pass from a synchronous
1506 * @param {String} moduleName the name of the module to potentially complete.
1508 completeLoad: function (moduleName) {
1511 context.takeGlobalQueue();
1513 while (defQueue.length) {
1514 args = defQueue.shift();
1516 if (args[0] === null) {
1517 args[0] = moduleName;
1519 } else if (args[0] === moduleName) {
1520 //Found matching define call for this script!
1523 //Some other named define call, most likely the result
1524 //of a build layer that included many define calls.
1532 //A script that does not call define(), so just simulate
1533 //the call for it. Special exception for jQuery dynamic load.
1534 callDefMain([moduleName, [],
1535 moduleName === "jquery" && typeof jQuery !== "undefined" ?
1541 //Doing this scriptCount decrement branching because sync envs
1542 //need to decrement after resume, otherwise it looks like
1543 //loading is complete after the first dependency is fetched.
1544 //For browsers, it works fine to decrement after, but it means
1545 //the checkLoaded setTimeout 50 ms cost is taken. To avoid
1546 //that cost, decrement beforehand.
1548 context.scriptCount -= 1;
1552 context.scriptCount -= 1;
1557 * Converts a module name + .extension into an URL path.
1558 * *Requires* the use of a module name. It does not support using
1559 * plain URLs like nameToUrl.
1561 toUrl: function (moduleNamePlusExt, relModuleMap) {
1562 var index = moduleNamePlusExt.lastIndexOf("."),
1566 ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
1567 moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
1570 return context.nameToUrl(moduleNamePlusExt, ext, relModuleMap);
1574 * Converts a module name to a file path. Supports cases where
1575 * moduleName may actually be just an URL.
1577 nameToUrl: function (moduleName, ext, relModuleMap) {
1578 var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
1579 config = context.config;
1581 //Normalize module name if have a base relative module name to work from.
1582 moduleName = normalize(moduleName, relModuleMap && relModuleMap.fullName);
1584 //If a colon is in the URL, it indicates a protocol is used and it is just
1585 //an URL to a file, or if it starts with a slash or ends with .js, it is just a plain file.
1586 //The slash is important for protocol-less URLs as well as full paths.
1587 if (req.jsExtRegExp.test(moduleName)) {
1588 //Just a plain path, not module name lookup, so just return it.
1589 //Add extension if it is included. This is a bit wonky, only non-.js things pass
1590 //an extension, this method probably needs to be reworked.
1591 url = moduleName + (ext ? ext : "");
1593 //A module that needs to be converted to a path.
1594 paths = config.paths;
1597 syms = moduleName.split("/");
1598 //For each module name segment, see if there is a path
1599 //registered for it. Start with most specific name
1600 //and work up from it.
1601 for (i = syms.length; i > 0; i--) {
1602 parentModule = syms.slice(0, i).join("/");
1603 if (paths[parentModule]) {
1604 syms.splice(0, i, paths[parentModule]);
1606 } else if ((pkg = pkgs[parentModule])) {
1607 //If module name is just the package name, then looking
1608 //for the main module.
1609 if (moduleName === pkg.name) {
1610 pkgPath = pkg.location + '/' + pkg.main;
1612 pkgPath = pkg.location;
1614 syms.splice(0, i, pkgPath);
1619 //Join the path parts together, then figure out if baseUrl is needed.
1620 url = syms.join("/") + (ext || ".js");
1621 url = (url.charAt(0) === '/' || url.match(/^\w+:/) ? "" : config.baseUrl) + url;
1624 return config.urlArgs ? url +
1625 ((url.indexOf('?') === -1 ? '?' : '&') +
1626 config.urlArgs) : url;
1630 //Make these visible on the context so can be called at the very
1631 //end of the file to bootstrap
1632 context.jQueryCheck = jQueryCheck;
1633 context.resume = resume;
1641 * If the only argument to require is a string, then the module that
1642 * is represented by that string is fetched for the appropriate context.
1644 * If the first argument is an array, then it will be treated as an array
1645 * of dependency string names to fetch. An optional function callback can
1646 * be specified to execute when all of those dependencies are available.
1648 * Make a local req variable to help Caja compliance (it assumes things
1649 * on a require that are not standardized), and to give a short
1650 * name for minification/local scope use.
1652 req = requirejs = function (deps, callback) {
1654 //Find the right context, use default
1655 var contextName = defContextName,
1658 // Determine if have config object in the call.
1659 if (!isArray(deps) && typeof deps !== "string") {
1660 // deps is a config object
1662 if (isArray(callback)) {
1663 // Adjust args if there are dependencies
1665 callback = arguments[2];
1671 if (config && config.context) {
1672 contextName = config.context;
1675 context = contexts[contextName] ||
1676 (contexts[contextName] = newContext(contextName));
1679 context.configure(config);
1682 return context.require(deps, callback);
1686 * Support require.config() to make it easier to cooperate with other
1687 * AMD loaders on globally agreed names.
1689 req.config = function (config) {
1694 * Export require as a global, but only if it does not already exist.
1701 * Global require.toUrl(), to match global require, mostly useful
1702 * for debugging/work in the global space.
1704 req.toUrl = function (moduleNamePlusExt) {
1705 return contexts[defContextName].toUrl(moduleNamePlusExt);
1708 req.version = version;
1710 //Used to filter out dependencies that are already paths.
1711 req.jsExtRegExp = /^\/|:|\?|\.js$/;
1714 //Stores a list of URLs that should not get async script tag treatment.
1718 req.isAsync = req.isBrowser = isBrowser;
1720 head = s.head = document.getElementsByTagName("head")[0];
1721 //If BASE tag is in play, using appendChild is a problem for IE6.
1722 //When that browser dies, this can be removed. Details in this jQuery bug:
1723 //http://dev.jquery.com/ticket/2709
1724 baseElement = document.getElementsByTagName("base")[0];
1726 head = s.head = baseElement.parentNode;
1731 * Any errors that require explicitly generates will be passed to this
1732 * function. Intercept/override it if you want custom error handling.
1733 * @param {Error} err the error object.
1735 req.onError = function (err) {
1740 * Does the request to load a module for the browser case.
1741 * Make this a separate function to allow other environments
1744 * @param {Object} context the require context to find state.
1745 * @param {String} moduleName the name of the module.
1746 * @param {Object} url the URL to the module.
1748 req.load = function (context, moduleName, url) {
1749 req.resourcesReady(false);
1751 context.scriptCount += 1;
1752 req.attach(url, context, moduleName);
1754 //If tracking a jQuery, then make sure its ready callbacks
1755 //are put on hold to prevent its ready callbacks from
1756 //triggering too soon.
1757 if (context.jQuery && !context.jQueryIncremented) {
1758 jQueryHoldReady(context.jQuery, true);
1759 context.jQueryIncremented = true;
1763 function getInteractiveScript() {
1764 var scripts, i, script;
1765 if (interactiveScript && interactiveScript.readyState === 'interactive') {
1766 return interactiveScript;
1769 scripts = document.getElementsByTagName('script');
1770 for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) {
1771 if (script.readyState === 'interactive') {
1772 return (interactiveScript = script);
1780 * The function that handles definitions of modules. Differs from
1781 * require() in that a string for the module should be the first argument,
1782 * and the function to execute after dependencies are loaded should
1783 * return a value to define the module corresponding to the first argument's
1786 define = function (name, deps, callback) {
1789 //Allow for anonymous functions
1790 if (typeof name !== 'string') {
1791 //Adjust args appropriately
1797 //This module may not have dependencies
1798 if (!isArray(deps)) {
1803 //If no name, and callback is a function, then figure out if it a
1804 //CommonJS thing with dependencies.
1805 if (!deps.length && isFunction(callback)) {
1806 //Remove comments from the callback string,
1807 //look for require calls, and pull them into the dependencies,
1808 //but only if there are function args.
1809 if (callback.length) {
1812 .replace(commentRegExp, "")
1813 .replace(cjsRequireRegExp, function (match, dep) {
1817 //May be a CommonJS thing even without require calls, but still
1818 //could use exports, and module. Avoid doing exports and module
1819 //work though if it just needs require.
1820 //REQUIRES the function to expect the CommonJS variables in the
1821 //order listed below.
1822 deps = (callback.length === 1 ? ["require"] : ["require", "exports", "module"]).concat(deps);
1826 //If in IE 6-8 and hit an anonymous define() call, do the interactive
1828 if (useInteractive) {
1829 node = currentlyAddingScript || getInteractiveScript();
1832 name = node.getAttribute("data-requiremodule");
1834 context = contexts[node.getAttribute("data-requirecontext")];
1838 //Always save off evaluating the def call until the script onload handler.
1839 //This allows multiple modules to be in a file without prematurely
1840 //tracing dependencies, and allows for anonymous module support,
1841 //where the module name is not known until the script onload event
1842 //occurs. If no context, use the global queue, and get it processed
1843 //in the onscript load callback.
1844 (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
1856 * Executes the text. Normally just uses eval, but can be modified
1857 * to use a more environment specific call.
1858 * @param {String} text the text to execute/evaluate.
1860 req.exec = function (text) {
1865 * Executes a module callack function. Broken out as a separate function
1866 * solely to allow the build system to sequence the files in the built
1867 * layer in the right sequence.
1871 req.execCb = function (name, callback, args, exports) {
1872 return callback.apply(exports, args);
1877 * Adds a node to the DOM. Public function since used by the order plugin.
1878 * This method should not normally be called by outside code.
1880 req.addScriptToDom = function (node) {
1881 //For some cache cases in IE 6-8, the script executes before the end
1882 //of the appendChild execution, so to tie an anonymous define
1883 //call to the module name (which is stored on the node), hold on
1884 //to a reference to this node, but clear after the DOM insertion.
1885 currentlyAddingScript = node;
1887 head.insertBefore(node, baseElement);
1889 head.appendChild(node);
1891 currentlyAddingScript = null;
1895 * callback for script loads, used to check status of loading.
1897 * @param {Event} evt the event from the browser for the script
1902 req.onScriptLoad = function (evt) {
1903 //Using currentTarget instead of target for Firefox 2.0's sake. Not
1904 //all old browsers will be supported, but this one was easy enough
1905 //to support and still makes sense.
1906 var node = evt.currentTarget || evt.srcElement, contextName, moduleName,
1909 if (evt.type === "load" || (node && readyRegExp.test(node.readyState))) {
1910 //Reset interactive script so a script node is not held onto for
1912 interactiveScript = null;
1914 //Pull out the name of the module and the context.
1915 contextName = node.getAttribute("data-requirecontext");
1916 moduleName = node.getAttribute("data-requiremodule");
1917 context = contexts[contextName];
1919 contexts[contextName].completeLoad(moduleName);
1921 //Clean up script binding. Favor detachEvent because of IE9
1922 //issue, see attachEvent/addEventListener comment elsewhere
1924 if (node.detachEvent && !isOpera) {
1925 //Probably IE. If not it will throw an error, which will be
1927 node.detachEvent("onreadystatechange", req.onScriptLoad);
1929 node.removeEventListener("load", req.onScriptLoad, false);
1935 * Attaches the script represented by the URL to the current
1936 * environment. Right now only supports browser loading,
1937 * but can be redefined in other environments to do the right thing.
1938 * @param {String} url the url of the script to attach.
1939 * @param {Object} context the context that wants the script.
1940 * @param {moduleName} the name of the module that is associated with the script.
1941 * @param {Function} [callback] optional callback, defaults to require.onScriptLoad
1942 * @param {String} [type] optional type, defaults to text/javascript
1943 * @param {Function} [fetchOnlyFunction] optional function to indicate the script node
1944 * should be set up to fetch the script but do not attach it to the DOM
1945 * so that it can later be attached to execute it. This is a way for the
1946 * order plugin to support ordered loading in IE. Once the script is fetched,
1947 * but not executed, the fetchOnlyFunction will be called.
1949 req.attach = function (url, context, moduleName, callback, type, fetchOnlyFunction) {
1952 //In the browser so use a script tag
1953 callback = callback || req.onScriptLoad;
1954 node = context && context.config && context.config.xhtml ?
1955 document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") :
1956 document.createElement("script");
1957 node.type = type || (context && context.config.scriptType) ||
1959 node.charset = "utf-8";
1960 //Use async so Gecko does not block on executing the script if something
1961 //like a long-polling comet tag is being run first. Gecko likes
1962 //to evaluate scripts in DOM order, even for dynamic scripts.
1963 //It will fetch them async, but only evaluate the contents in DOM
1964 //order, so a long-polling script tag can delay execution of scripts
1965 //after it. But telling Gecko we expect async gets us the behavior
1966 //we want -- execute it whenever it is finished downloading. Only
1967 //Helps Firefox 3.6+
1968 //Allow some URLs to not be fetched async. Mostly helps the order!
1970 node.async = !s.skipAsync[url];
1973 node.setAttribute("data-requirecontext", context.contextName);
1975 node.setAttribute("data-requiremodule", moduleName);
1977 //Set up load listener. Test attachEvent first because IE9 has
1978 //a subtle issue in its addEventListener and script onload firings
1979 //that do not match the behavior of all other browsers with
1980 //addEventListener support, which fire the onload event for a
1981 //script right after the script execution. See:
1982 //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
1983 //UNFORTUNATELY Opera implements attachEvent but does not follow the script
1984 //script execution mode.
1985 if (node.attachEvent && !isOpera) {
1986 //Probably IE. IE (at least 6-8) do not fire
1987 //script onload right after executing the script, so
1988 //we cannot tie the anonymous define call to a name.
1989 //However, IE reports the script as being in "interactive"
1990 //readyState at the time of the define call.
1991 useInteractive = true;
1994 if (fetchOnlyFunction) {
1995 //Need to use old school onreadystate here since
1996 //when the event fires and the node is not attached
1997 //to the DOM, the evt.srcElement is null, so use
1998 //a closure to remember the node.
1999 node.onreadystatechange = function (evt) {
2000 //Script loaded but not executed.
2001 //Clear loaded handler, set the real one that
2002 //waits for script execution.
2003 if (node.readyState === 'loaded') {
2004 node.onreadystatechange = null;
2005 node.attachEvent("onreadystatechange", callback);
2006 fetchOnlyFunction(node);
2010 node.attachEvent("onreadystatechange", callback);
2013 node.addEventListener("load", callback, false);
2017 //Fetch only means waiting to attach to DOM after loaded.
2018 if (!fetchOnlyFunction) {
2019 req.addScriptToDom(node);
2023 } else if (isWebWorker) {
2024 //In a web worker, use importScripts. This is not a very
2025 //efficient use of importScripts, importScripts will block until
2026 //its script is downloaded and evaluated. However, if web workers
2027 //are in play, the expectation that a build has been done so that
2028 //only one script needs to be loaded anyway. This may need to be
2029 //reevaluated if other use cases become common.
2032 //Account for anonymous modules
2033 context.completeLoad(moduleName);
2038 //Look for a data-main script attribute, which could also adjust the baseUrl.
2040 //Figure out baseUrl. Get it from the script tag with require.js in it.
2041 scripts = document.getElementsByTagName("script");
2043 for (globalI = scripts.length - 1; globalI > -1 && (script = scripts[globalI]); globalI--) {
2044 //Set the "head" where we can append children by
2045 //using the script's parent.
2047 head = script.parentNode;
2050 //Look for a data-main attribute to set main script for the page
2051 //to load. If it is there, the path to data main becomes the
2052 //baseUrl, if it is not already set.
2053 if ((dataMain = script.getAttribute('data-main'))) {
2055 //Pull off the directory of data-main for use as the
2057 src = dataMain.split('/');
2058 mainScript = src.pop();
2059 subPath = src.length ? src.join('/') + '/' : './';
2062 cfg.baseUrl = subPath;
2063 //Strip off any trailing .js since dataMain is now
2064 //like a module name.
2065 dataMain = mainScript.replace(jsSuffixRegExp, '');
2068 //Put the data-main script in the files to load.
2069 cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
2076 //See if there is nothing waiting across contexts, and if not, trigger
2078 req.checkReadyState = function () {
2079 var contexts = s.contexts, prop;
2080 for (prop in contexts) {
2081 if (!(prop in empty)) {
2082 if (contexts[prop].waitCount) {
2087 req.resourcesReady(true);
2091 * Internal function that is triggered whenever all scripts/resources
2092 * have been loaded by the loader. Can be overridden by other, for
2093 * instance the domReady plugin, which wants to know when all resources
2096 req.resourcesReady = function (isReady) {
2097 var contexts, context, prop;
2099 //First, set the public variable indicating that resources are loading.
2100 req.resourcesDone = isReady;
2102 if (req.resourcesDone) {
2103 //If jQuery with DOM ready delayed, release it now.
2104 contexts = s.contexts;
2105 for (prop in contexts) {
2106 if (!(prop in empty)) {
2107 context = contexts[prop];
2108 if (context.jQueryIncremented) {
2109 jQueryHoldReady(context.jQuery, false);
2110 context.jQueryIncremented = false;
2117 //FF < 3.6 readyState fix. Needed so that domReady plugin
2118 //works well in that environment, since require.js is normally
2119 //loaded via an HTML script tag so it will be there before window load,
2120 //where the domReady plugin is more likely to be loaded after window load.
2121 req.pageLoaded = function () {
2122 if (document.readyState !== "complete") {
2123 document.readyState = "complete";
2127 if (document.addEventListener) {
2128 if (!document.readyState) {
2129 document.readyState = "loading";
2130 window.addEventListener("load", req.pageLoaded, false);
2135 //Set up default context. If require was a configuration object, use that as base config.
2138 //If modules are built into require.js, then need to make sure dependencies are
2139 //traced. Use a setTimeout in the browser world, to allow all the modules to register
2140 //themselves. In a non-browser env, assume that modules are not built into require.js,
2141 //which seems odd to do on the server.
2142 if (req.isAsync && typeof setTimeout !== "undefined") {
2143 ctx = s.contexts[(cfg.context || defContextName)];
2144 //Indicate that the script that includes require() is still loading,
2145 //so that require()'d dependencies are not traced until the end of the
2146 //file is parsed (approximated via the setTimeout call).
2147 ctx.requireWait = true;
2148 setTimeout(function () {
2149 ctx.requireWait = false;
2151 if (!ctx.scriptCount) {
2154 req.checkReadyState();
2160 if (env === 'rhino') {
2162 * @license RequireJS rhino Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2163 * Available via the MIT or new BSD license.
2164 * see: http://github.com/jrburke/requirejs for details
2167 /*jslint strict: false */
2168 /*global require: false, java: false, load: false */
2172 require.load = function (context, moduleName, url) {
2173 //Indicate a the module is in process of loading.
2174 context.scriptCount += 1;
2178 //Support anonymous modules.
2179 context.completeLoad(moduleName);
2183 } else if (env === 'node') {
2184 this.requirejsVars = {
2188 nodeRequire: nodeRequire
2190 require.nodeRequire = nodeRequire;
2193 * @license RequireJS node Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2194 * Available via the MIT or new BSD license.
2195 * see: http://github.com/jrburke/requirejs for details
2198 /*jslint regexp: false, strict: false */
2199 /*global require: false, define: false, requirejsVars: false, process: false */
2202 * This adapter assumes that x.js has loaded it and set up
2203 * some variables. This adapter just allows limited RequireJS
2204 * usage from within the requirejs directory. The general
2205 * node adapater is r.js.
2209 var nodeReq = requirejsVars.nodeRequire,
2210 req = requirejsVars.require,
2211 def = requirejsVars.define,
2213 path = nodeReq('path'),
2216 //Supply an implementation that allows synchronous get of a module.
2217 req.get = function (context, moduleName, relModuleMap) {
2218 if (moduleName === "require" || moduleName === "exports" || moduleName === "module") {
2219 req.onError(new Error("Explicit require of " + moduleName + " is not allowed."));
2223 moduleMap = context.makeModuleMap(moduleName, relModuleMap);
2225 //Normalize module name, if it contains . or ..
2226 moduleName = moduleMap.fullName;
2228 if (moduleName in context.defined) {
2229 ret = context.defined[moduleName];
2231 if (ret === undefined) {
2232 //Try to dynamically fetch it.
2233 req.load(context, moduleName, moduleMap.url);
2234 //The above call is sync, so can do the next thing safely.
2235 ret = context.defined[moduleName];
2242 //Add wrapper around the code so that it gets the requirejs
2243 //API instead of the Node API, and it is done lexically so
2244 //that it survives later execution.
2245 req.makeNodeWrapper = function (contents) {
2246 return '(function (require, requirejs, define) { ' +
2248 '\n}(requirejsVars.require, requirejsVars.requirejs, requirejsVars.define));';
2251 requirejsVars.nodeLoad = req.load = function (context, moduleName, url) {
2254 //Indicate a the module is in process of loading.
2255 context.scriptCount += 1;
2257 if (path.existsSync(url)) {
2258 contents = fs.readFileSync(url, 'utf8');
2260 contents = req.makeNodeWrapper(contents);
2262 vm.runInThisContext(contents, fs.realpathSync(url));
2264 err = new Error('Evaluating ' + url + ' as module "' +
2265 moduleName + '" failed with error: ' + e);
2266 err.originalError = e;
2267 err.moduleName = moduleName;
2269 return req.onError(err);
2272 def(moduleName, function () {
2274 return (context.config.nodeRequire || req.nodeRequire)(moduleName);
2276 err = new Error('Calling node\'s require("' +
2277 moduleName + '") failed with error: ' + e);
2278 err.originalError = e;
2279 err.moduleName = moduleName;
2280 return req.onError(err);
2285 //Support anonymous modules.
2286 context.completeLoad(moduleName);
2291 //Override to provide the function wrapper for define/require.
2292 req.exec = function (text) {
2293 /*jslint evil: true */
2294 text = req.makeNodeWrapper(text);
2298 //Hold on to the original execCb to use in useLib calls.
2299 requirejsVars.nodeRequireExecCb = require.execCb;
2304 //Support a default file name to execute. Useful for hosted envs
2305 //like Joyent where it defaults to a server.js as the only executed
2306 //script. But only do it if this is not an optimization run.
2307 if (commandOption !== 'o' && (!fileName || !jsSuffixRegExp.test(fileName))) {
2308 fileName = 'main.js';
2312 * Loads the library files that can be used for the optimizer, or for other
2315 function loadLib() {
2317 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2318 * Available via the MIT or new BSD license.
2319 * see: http://github.com/jrburke/requirejs for details
2322 /*jslint strict: false */
2323 /*global Packages: false, process: false, window: false, navigator: false,
2324 document: false, define: false */
2327 * A plugin that modifies any /env/ path to be the right path based on
2328 * the host environment. Right now only works for Node, Rhino and browser.
2331 var pathRegExp = /(\/|^)env\/|\{env\}/,
2334 if (typeof Packages !== 'undefined') {
2336 } else if (typeof process !== 'undefined') {
2338 } else if (typeof window !== "undefined" && navigator && document) {
2343 load: function (name, req, load, config) {
2344 //Allow override in the config.
2349 name = name.replace(pathRegExp, function (match, prefix) {
2350 if (match.indexOf('{') === -1) {
2351 return prefix + env + '/';
2357 req([name], function (mod) {
2363 if(env === 'node') {
2365 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2366 * Available via the MIT or new BSD license.
2367 * see: http://github.com/jrburke/requirejs for details
2370 /*jslint strict: false */
2371 /*global define: false, process: false */
2373 define('node/args', function () {
2374 //Do not return the "node" or "r.js" arguments
2375 var args = process.argv.slice(2);
2377 //Ignore any command option used for rq.js
2378 if (args[0] && args[0].indexOf('-' === 0)) {
2379 args = args.slice(1);
2387 if(env === 'rhino') {
2389 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2390 * Available via the MIT or new BSD license.
2391 * see: http://github.com/jrburke/requirejs for details
2394 /*jslint strict: false */
2395 /*global define: false, process: false */
2397 var jsLibRhinoArgs = (typeof rhinoArgs !== 'undefined' && rhinoArgs) || [].concat(Array.prototype.slice.call(arguments, 0));
2399 define('rhino/args', function () {
2400 var args = jsLibRhinoArgs;
2402 //Ignore any command option used for rq.js
2403 if (args[0] && args[0].indexOf('-' === 0)) {
2404 args = args.slice(1);
2412 if(env === 'node') {
2414 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2415 * Available via the MIT or new BSD license.
2416 * see: http://github.com/jrburke/requirejs for details
2419 /*jslint strict: false */
2420 /*global define: false, console: false */
2422 define('node/load', ['fs'], function (fs) {
2423 function load(fileName) {
2424 var contents = fs.readFileSync(fileName, 'utf8');
2425 process.compile(contents, fileName);
2433 if(env === 'rhino') {
2435 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2436 * Available via the MIT or new BSD license.
2437 * see: http://github.com/jrburke/requirejs for details
2440 /*jslint strict: false */
2441 /*global define: false, load: false */
2443 define('rhino/load', function () {
2449 if(env === 'node') {
2451 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2452 * Available via the MIT or new BSD license.
2453 * see: http://github.com/jrburke/requirejs for details
2456 /*jslint plusplus: false, octal:false, strict: false */
2457 /*global define: false, process: false */
2459 define('node/file', ['fs', 'path'], function (fs, path) {
2461 var isWindows = process.platform === 'win32',
2462 windowsDriveRegExp = /^[a-zA-Z]\:\/$/,
2465 function frontSlash(path) {
2466 return path.replace(/\\/g, '/');
2469 function exists(path) {
2470 if (isWindows && path.charAt(path.length - 1) === '/' &&
2471 path.charAt(path.length - 2) !== ':') {
2472 path = path.substring(0, path.length - 1);
2483 function mkDir(dir) {
2484 if (!exists(dir) && (!isWindows || !windowsDriveRegExp.test(dir))) {
2485 fs.mkdirSync(dir, 511);
2489 function mkFullDir(dir) {
2490 var parts = dir.split('/'),
2494 parts.forEach(function (part) {
2495 //First part may be empty string if path starts with a slash.
2496 currDir += part + '/';
2506 backSlashRegExp: /\\/g,
2507 exclusionRegExp: /^\./,
2508 getLineSeparator: function () {
2512 exists: function (fileName) {
2513 return exists(fileName);
2516 parent: function (fileName) {
2517 var parts = fileName.split('/');
2519 return parts.join('/');
2523 * Gets the absolute file path as a string, normalized
2524 * to using front slashes for path separators.
2525 * @param {String} fileName
2527 absPath: function (fileName) {
2528 return frontSlash(path.normalize(frontSlash(fs.realpathSync(fileName))));
2531 normalize: function (fileName) {
2532 return frontSlash(path.normalize(fileName));
2535 isFile: function (path) {
2536 return fs.statSync(path).isFile();
2539 isDirectory: function (path) {
2540 return fs.statSync(path).isDirectory();
2543 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths) {
2544 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
2545 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
2546 //and it will be treated as the "include" case.
2547 //Ignores files/directories that start with a period (.) unless exclusionRegExp
2548 //is set to another value.
2549 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
2550 i, stat, filePath, ok, dirFiles, fileName;
2554 regExpInclude = regExpFilters.include || regExpFilters;
2555 regExpExclude = regExpFilters.exclude || null;
2557 if (file.exists(topDir)) {
2558 dirFileArray = fs.readdirSync(topDir);
2559 for (i = 0; i < dirFileArray.length; i++) {
2560 fileName = dirFileArray[i];
2561 filePath = path.join(topDir, fileName);
2562 stat = fs.statSync(filePath);
2563 if (stat.isFile()) {
2564 if (makeUnixPaths) {
2565 //Make sure we have a JS string.
2566 if (filePath.indexOf("/") === -1) {
2567 filePath = frontSlash(filePath);
2572 if (regExpInclude) {
2573 ok = filePath.match(regExpInclude);
2575 if (ok && regExpExclude) {
2576 ok = !filePath.match(regExpExclude);
2579 if (ok && (!file.exclusionRegExp ||
2580 !file.exclusionRegExp.test(fileName))) {
2581 files.push(filePath);
2583 } else if (stat.isDirectory() &&
2584 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileName))) {
2585 dirFiles = this.getFilteredFileList(filePath, regExpFilters, makeUnixPaths);
2586 files.push.apply(files, dirFiles);
2591 return files; //Array
2594 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
2595 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
2596 //file should be copied. Returns a list file name strings of the destinations that were copied.
2597 regExpFilter = regExpFilter || /\w/;
2599 //Normalize th directory names, but keep front slashes.
2600 //path module on windows now returns backslashed paths.
2601 srcDir = frontSlash(path.normalize(srcDir));
2602 destDir = frontSlash(path.normalize(destDir));
2604 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
2605 copiedFiles = [], i, srcFileName, destFileName;
2607 for (i = 0; i < fileNames.length; i++) {
2608 srcFileName = fileNames[i];
2609 destFileName = srcFileName.replace(srcDir, destDir);
2611 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
2612 copiedFiles.push(destFileName);
2616 return copiedFiles.length ? copiedFiles : null; //Array or null
2619 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
2620 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
2621 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
2624 //logger.trace("Src filename: " + srcFileName);
2625 //logger.trace("Dest filename: " + destFileName);
2627 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
2630 if (file.exists(destFileName) && fs.statSync(destFileName).mtime.getTime() >= fs.statSync(srcFileName).mtime.getTime()) {
2631 return false; //Boolean
2635 //Make sure destination dir exists.
2636 parentDir = path.dirname(destFileName);
2637 if (!file.exists(parentDir)) {
2638 mkFullDir(parentDir);
2641 fs.writeFileSync(destFileName, fs.readFileSync(srcFileName, 'binary'), 'binary');
2643 return true; //Boolean
2647 * Renames a file. May fail if "to" already exists or is on another drive.
2649 renameFile: function (from, to) {
2650 return fs.renameSync(from, to);
2654 * Reads a *text* file.
2656 readFile: function (/*String*/path, /*String?*/encoding) {
2657 if (encoding === 'utf-8') {
2664 var text = fs.readFileSync(path, encoding);
2666 //Hmm, would not expect to get A BOM, but it seems to happen,
2667 //remove it just in case.
2668 if (text.indexOf('\uFEFF') === 0) {
2669 text = text.substring(1, text.length);
2675 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
2676 //summary: saves a *text* file using UTF-8 encoding.
2677 file.saveFile(fileName, fileContents, "utf8");
2680 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
2681 //summary: saves a *text* file.
2684 if (encoding === 'utf-8') {
2691 //Make sure destination directories exist.
2692 parentDir = path.dirname(fileName);
2693 if (!file.exists(parentDir)) {
2694 mkFullDir(parentDir);
2697 fs.writeFileSync(fileName, fileContents, encoding);
2700 deleteFile: function (/*String*/fileName) {
2701 //summary: deletes a file or directory if it exists.
2703 if (file.exists(fileName)) {
2704 stat = fs.statSync(fileName);
2705 if (stat.isDirectory()) {
2706 files = fs.readdirSync(fileName);
2707 for (i = 0; i < files.length; i++) {
2708 this.deleteFile(path.join(fileName, files[i]));
2710 fs.rmdirSync(fileName);
2712 fs.unlinkSync(fileName);
2724 if(env === 'rhino') {
2726 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2727 * Available via the MIT or new BSD license.
2728 * see: http://github.com/jrburke/requirejs for details
2730 //Helper functions to deal with file I/O.
2732 /*jslint plusplus: false, strict: false */
2733 /*global java: false, define: false */
2735 define('rhino/file', function () {
2737 backSlashRegExp: /\\/g,
2739 exclusionRegExp: /^\./,
2741 getLineSeparator: function () {
2742 return file.lineSeparator;
2745 lineSeparator: java.lang.System.getProperty("line.separator"), //Java String
2747 exists: function (fileName) {
2748 return (new java.io.File(fileName)).exists();
2751 parent: function (fileName) {
2752 return file.absPath((new java.io.File(fileName)).getParentFile());
2755 normalize: function (fileName) {
2756 return file.absPath(fileName);
2759 isFile: function (path) {
2760 return (new java.io.File(path)).isFile();
2763 isDirectory: function (path) {
2764 return (new java.io.File(path)).isDirectory();
2768 * Gets the absolute file path as a string, normalized
2769 * to using front slashes for path separators.
2770 * @param {java.io.File||String} file
2772 absPath: function (fileObj) {
2773 if (typeof fileObj === "string") {
2774 fileObj = new java.io.File(fileObj);
2776 return (fileObj.getAbsolutePath() + "").replace(file.backSlashRegExp, "/");
2779 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) {
2780 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
2781 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
2782 //and it will be treated as the "include" case.
2783 //Ignores files/directories that start with a period (.) unless exclusionRegExp
2784 //is set to another value.
2785 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
2786 i, fileObj, filePath, ok, dirFiles;
2789 if (!startDirIsJavaObject) {
2790 topDir = new java.io.File(startDir);
2793 regExpInclude = regExpFilters.include || regExpFilters;
2794 regExpExclude = regExpFilters.exclude || null;
2796 if (topDir.exists()) {
2797 dirFileArray = topDir.listFiles();
2798 for (i = 0; i < dirFileArray.length; i++) {
2799 fileObj = dirFileArray[i];
2800 if (fileObj.isFile()) {
2801 filePath = fileObj.getPath();
2802 if (makeUnixPaths) {
2803 //Make sure we have a JS string.
2804 filePath = String(filePath);
2805 if (filePath.indexOf("/") === -1) {
2806 filePath = filePath.replace(/\\/g, "/");
2811 if (regExpInclude) {
2812 ok = filePath.match(regExpInclude);
2814 if (ok && regExpExclude) {
2815 ok = !filePath.match(regExpExclude);
2818 if (ok && (!file.exclusionRegExp ||
2819 !file.exclusionRegExp.test(fileObj.getName()))) {
2820 files.push(filePath);
2822 } else if (fileObj.isDirectory() &&
2823 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.getName()))) {
2824 dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true);
2825 files.push.apply(files, dirFiles);
2830 return files; //Array
2833 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
2834 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
2835 //file should be copied. Returns a list file name strings of the destinations that were copied.
2836 regExpFilter = regExpFilter || /\w/;
2838 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
2839 copiedFiles = [], i, srcFileName, destFileName;
2841 for (i = 0; i < fileNames.length; i++) {
2842 srcFileName = fileNames[i];
2843 destFileName = srcFileName.replace(srcDir, destDir);
2845 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
2846 copiedFiles.push(destFileName);
2850 return copiedFiles.length ? copiedFiles : null; //Array or null
2853 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
2854 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
2855 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
2856 var destFile = new java.io.File(destFileName), srcFile, parentDir,
2857 srcChannel, destChannel;
2859 //logger.trace("Src filename: " + srcFileName);
2860 //logger.trace("Dest filename: " + destFileName);
2862 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
2865 srcFile = new java.io.File(srcFileName);
2866 if (destFile.exists() && destFile.lastModified() >= srcFile.lastModified()) {
2867 return false; //Boolean
2871 //Make sure destination dir exists.
2872 parentDir = destFile.getParentFile();
2873 if (!parentDir.exists()) {
2874 if (!parentDir.mkdirs()) {
2875 throw "Could not create directory: " + parentDir.getAbsolutePath();
2879 //Java's version of copy file.
2880 srcChannel = new java.io.FileInputStream(srcFileName).getChannel();
2881 destChannel = new java.io.FileOutputStream(destFileName).getChannel();
2882 destChannel.transferFrom(srcChannel, 0, srcChannel.size());
2884 destChannel.close();
2886 return true; //Boolean
2890 * Renames a file. May fail if "to" already exists or is on another drive.
2892 renameFile: function (from, to) {
2893 return (new java.io.File(from)).renameTo((new java.io.File(to)));
2896 readFile: function (/*String*/path, /*String?*/encoding) {
2897 //A file read function that can deal with BOMs
2898 encoding = encoding || "utf-8";
2899 var fileObj = new java.io.File(path),
2900 input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(fileObj), encoding)),
2903 stringBuffer = new java.lang.StringBuffer();
2904 line = input.readLine();
2906 // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
2907 // http://www.unicode.org/faq/utf_bom.html
2909 // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
2910 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
2911 if (line && line.length() && line.charAt(0) === 0xfeff) {
2912 // Eat the BOM, since we've already found the encoding on this file,
2913 // and we plan to concatenating this buffer with others; the BOM should
2914 // only appear at the top of a file.
2915 line = line.substring(1);
2917 while (line !== null) {
2918 stringBuffer.append(line);
2919 stringBuffer.append(file.lineSeparator);
2920 line = input.readLine();
2922 //Make sure we return a JavaScript string and not a Java string.
2923 return String(stringBuffer.toString()); //String
2929 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
2930 //summary: saves a file using UTF-8 encoding.
2931 file.saveFile(fileName, fileContents, "utf-8");
2934 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
2935 //summary: saves a file.
2936 var outFile = new java.io.File(fileName), outWriter, parentDir, os;
2938 parentDir = outFile.getAbsoluteFile().getParentFile();
2939 if (!parentDir.exists()) {
2940 if (!parentDir.mkdirs()) {
2941 throw "Could not create directory: " + parentDir.getAbsolutePath();
2946 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
2948 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
2951 os = new java.io.BufferedWriter(outWriter);
2953 os.write(fileContents);
2959 deleteFile: function (/*String*/fileName) {
2960 //summary: deletes a file or directory if it exists.
2961 var fileObj = new java.io.File(fileName), files, i;
2962 if (fileObj.exists()) {
2963 if (fileObj.isDirectory()) {
2964 files = fileObj.listFiles();
2965 for (i = 0; i < files.length; i++) {
2966 this.deleteFile(files[i]);
2969 fileObj["delete"]();
2979 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2980 * Available via the MIT or new BSD license.
2981 * see: http://github.com/jrburke/requirejs for details
2984 /*jslint plusplus: true */
2987 define('lang', function () {
2991 backSlashRegExp: /\\/g,
2992 ostring: Object.prototype.toString,
2994 isArray: Array.isArray || function (it) {
2995 return lang.ostring.call(it) === "[object Array]";
2998 isFunction: function(it) {
2999 return lang.ostring.call(it) === "[object Function]";
3002 isRegExp: function(it) {
3003 return it && it instanceof RegExp;
3006 _mixin: function(dest, source, override){
3008 for (name in source) {
3009 if(source.hasOwnProperty(name)
3010 && (override || !dest.hasOwnProperty(name))) {
3011 dest[name] = source[name];
3015 return dest; // Object
3019 * mixin({}, obj1, obj2) is allowed. If the last argument is a boolean,
3020 * then the source objects properties are force copied over to dest.
3022 mixin: function(dest){
3023 var parameters = Array.prototype.slice.call(arguments),
3026 if (!dest) { dest = {}; }
3028 if (parameters.length > 2 && typeof arguments[parameters.length-1] === 'boolean') {
3029 override = parameters.pop();
3032 for (i = 1, l = parameters.length; i < l; i++) {
3033 lang._mixin(dest, parameters[i], override);
3035 return dest; // Object
3038 delegate: (function () {
3039 // boodman/crockford delegation w/ cornford optimization
3041 return function (obj, props) {
3042 TMP.prototype = obj;
3043 var tmp = new TMP();
3044 TMP.prototype = null;
3046 lang.mixin(tmp, props);
3048 return tmp; // Object
3055 if(env === 'node') {
3057 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3058 * Available via the MIT or new BSD license.
3059 * see: http://github.com/jrburke/requirejs for details
3062 /*jslint strict: false */
3063 /*global define: false, console: false */
3065 define('node/print', function () {
3066 function print(msg) {
3075 if(env === 'rhino') {
3077 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3078 * Available via the MIT or new BSD license.
3079 * see: http://github.com/jrburke/requirejs for details
3082 /*jslint strict: false */
3083 /*global define: false, print: false */
3085 define('rhino/print', function () {
3091 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3092 * Available via the MIT or new BSD license.
3093 * see: http://github.com/jrburke/requirejs for details
3096 /*jslint nomen: false, strict: false */
3097 /*global define: false */
3099 define('logger', ['env!env/print'], function (print) {
3109 logLevel: function( level ) {
3113 trace: function (message) {
3114 if (this.level <= this.TRACE) {
3115 this._print(message);
3119 info: function (message) {
3120 if (this.level <= this.INFO) {
3121 this._print(message);
3125 warn: function (message) {
3126 if (this.level <= this.WARN) {
3127 this._print(message);
3131 error: function (message) {
3132 if (this.level <= this.ERROR) {
3133 this._print(message);
3137 _print: function (message) {
3138 this._sysPrint((this.logPrefix ? (this.logPrefix + " ") : "") + message);
3141 _sysPrint: function (message) {
3148 //Just a blank file to use when building the optimizer with the optimizer,
3149 //so that the build does not attempt to inline some env modules,
3150 //like Node's fs and path.
3152 //Just a blank file to use when building the optimizer with the optimizer,
3153 //so that the build does not attempt to inline some env modules,
3154 //like Node's fs and path.
3156 define('uglifyjs/parse-js', ["require", "exports", "module"], function(require, exports, module) {
3157 /***********************************************************************
3159 A JavaScript tokenizer / parser / beautifier / compressor.
3161 This version is suitable for Node.js. With minimal changes (the
3162 exports stuff) it should work on any JS platform.
3164 This file contains the tokenizer/parser. It is a port to JavaScript
3165 of parse-js [1], a JavaScript parser library written in Common Lisp
3166 by Marijn Haverbeke. Thank you Marijn!
3168 [1] http://marijn.haverbeke.nl/parse-js/
3172 - tokenizer(code) -- returns a function. Call the returned
3173 function to fetch the next token.
3175 - parse(code) -- returns an AST of the given JavaScript code.
3177 -------------------------------- (C) ---------------------------------
3180 <mihai.bazon@gmail.com>
3181 http://mihai.bazon.net/blog
3183 Distributed under the BSD license:
3185 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
3186 Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
3188 Redistribution and use in source and binary forms, with or without
3189 modification, are permitted provided that the following conditions
3192 * Redistributions of source code must retain the above
3193 copyright notice, this list of conditions and the following
3196 * Redistributions in binary form must reproduce the above
3197 copyright notice, this list of conditions and the following
3198 disclaimer in the documentation and/or other materials
3199 provided with the distribution.
3201 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
3202 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3203 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
3204 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
3205 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3206 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3207 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3208 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3209 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
3210 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3211 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3214 ***********************************************************************/
3216 /* -----[ Tokenizer (constants) ]----- */
3218 var KEYWORDS = array_to_hash([
3246 var RESERVED_WORDS = array_to_hash([
3279 var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
3288 var KEYWORDS_ATOM = array_to_hash([
3295 var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
3297 var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
3298 var RE_OCT_NUMBER = /^0[0-7]+$/;
3299 var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
3301 var OPERATORS = array_to_hash([
3348 var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
3350 var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
3352 var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
3354 var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
3356 /* -----[ Tokenizer ]----- */
3358 // regexps adapted from http://xregexp.com/plugins/#unicode
3360 letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
3361 non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
3362 space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
3363 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
3366 function is_letter(ch) {
3367 return UNICODE.letter.test(ch);
3370 function is_digit(ch) {
3371 ch = ch.charCodeAt(0);
3372 return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
3375 function is_alphanumeric_char(ch) {
3376 return is_digit(ch) || is_letter(ch);
3379 function is_unicode_combining_mark(ch) {
3380 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
3383 function is_unicode_connector_punctuation(ch) {
3384 return UNICODE.connector_punctuation.test(ch);
3387 function is_identifier_start(ch) {
3388 return ch == "$" || ch == "_" || is_letter(ch);
3391 function is_identifier_char(ch) {
3392 return is_identifier_start(ch)
3393 || is_unicode_combining_mark(ch)
3395 || is_unicode_connector_punctuation(ch)
3396 || ch == "\u200c" // zero-width non-joiner <ZWNJ>
3397 || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
3401 function parse_js_number(num) {
3402 if (RE_HEX_NUMBER.test(num)) {
3403 return parseInt(num.substr(2), 16);
3404 } else if (RE_OCT_NUMBER.test(num)) {
3405 return parseInt(num.substr(1), 8);
3406 } else if (RE_DEC_NUMBER.test(num)) {
3407 return parseFloat(num);
3411 function JS_Parse_Error(message, line, col, pos) {
3412 this.message = message;
3413 this.line = line + 1;
3416 this.stack = new Error().stack;
3419 JS_Parse_Error.prototype.toString = function() {
3420 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
3423 function js_error(message, line, col, pos) {
3424 throw new JS_Parse_Error(message, line, col, pos);
3427 function is_token(token, type, val) {
3428 return token.type == type && (val == null || token.value == val);
3433 function tokenizer($TEXT) {
3436 text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
3443 newline_before : false,
3444 regex_allowed : false,
3445 comments_before : []
3448 function peek() { return S.text.charAt(S.pos); };
3450 function next(signal_eof, in_string) {
3451 var ch = S.text.charAt(S.pos++);
3452 if (signal_eof && !ch)
3455 S.newline_before = S.newline_before || !in_string;
3468 function find(what, signal_eof) {
3469 var pos = S.text.indexOf(what, S.pos);
3470 if (signal_eof && pos == -1) throw EX_EOF;
3474 function start_token() {
3480 function token(type, value, is_comment) {
3481 S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
3482 (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
3483 (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
3491 nlb : S.newline_before
3494 ret.comments_before = S.comments_before;
3495 S.comments_before = [];
3497 S.newline_before = false;
3501 function skip_whitespace() {
3502 while (HOP(WHITESPACE_CHARS, peek()))
3506 function read_while(pred) {
3507 var ret = "", ch = peek(), i = 0;
3508 while (ch && pred(ch, i++)) {
3515 function parse_error(err) {
3516 js_error(err, S.tokline, S.tokcol, S.tokpos);
3519 function read_num(prefix) {
3520 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
3521 var num = read_while(function(ch, i){
3522 if (ch == "x" || ch == "X") {
3523 if (has_x) return false;
3524 return has_x = true;
3526 if (!has_x && (ch == "E" || ch == "e")) {
3527 if (has_e) return false;
3528 return has_e = after_e = true;
3531 if (after_e || (i == 0 && !prefix)) return true;
3534 if (ch == "+") return after_e;
3537 if (!has_dot && !has_x)
3538 return has_dot = true;
3541 return is_alphanumeric_char(ch);
3545 var valid = parse_js_number(num);
3546 if (!isNaN(valid)) {
3547 return token("num", valid);
3549 parse_error("Invalid syntax: " + num);
3553 function read_escaped_char(in_string) {
3554 var ch = next(true, in_string);
3556 case "n" : return "\n";
3557 case "r" : return "\r";
3558 case "t" : return "\t";
3559 case "b" : return "\b";
3560 case "v" : return "\u000b";
3561 case "f" : return "\f";
3562 case "0" : return "\0";
3563 case "x" : return String.fromCharCode(hex_bytes(2));
3564 case "u" : return String.fromCharCode(hex_bytes(4));
3565 case "\n": return "";
3566 default : return ch;
3570 function hex_bytes(n) {
3572 for (; n > 0; --n) {
3573 var digit = parseInt(next(true), 16);
3575 parse_error("Invalid hex-character pattern in string");
3576 num = (num << 4) | digit;
3581 function read_string() {
3582 return with_eof_error("Unterminated string constant", function(){
3583 var quote = next(), ret = "";
3585 var ch = next(true);
3587 // read OctalEscapeSequence (XXX: deprecated if "strict mode")
3588 // https://github.com/mishoo/UglifyJS/issues/178
3589 var octal_len = 0, first = null;
3590 ch = read_while(function(ch){
3591 if (ch >= "0" && ch <= "7") {
3596 else if (first <= "3" && octal_len <= 2) return ++octal_len;
3597 else if (first >= "4" && octal_len <= 1) return ++octal_len;
3601 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
3602 else ch = read_escaped_char(true);
3604 else if (ch == quote) break;
3607 return token("string", ret);
3611 function read_line_comment() {
3613 var i = find("\n"), ret;
3615 ret = S.text.substr(S.pos);
3616 S.pos = S.text.length;
3618 ret = S.text.substring(S.pos, i);
3621 return token("comment1", ret, true);
3624 function read_multiline_comment() {
3626 return with_eof_error("Unterminated multiline comment", function(){
3627 var i = find("*/", true),
3628 text = S.text.substring(S.pos, i);
3630 S.line += text.split("\n").length - 1;
3631 S.newline_before = text.indexOf("\n") >= 0;
3633 // https://github.com/mishoo/UglifyJS/issues/#issue/100
3634 if (/^@cc_on/i.test(text)) {
3635 warn("WARNING: at line " + S.line);
3636 warn("*** Found \"conditional comment\": " + text);
3637 warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer.");
3640 return token("comment2", text, true);
3644 function read_name() {
3645 var backslash = false, name = "", ch;
3646 while ((ch = peek()) != null) {
3648 if (ch == "\\") backslash = true, next();
3649 else if (is_identifier_char(ch)) name += next();
3653 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
3654 ch = read_escaped_char();
3655 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
3663 function read_regexp(regexp) {
3664 return with_eof_error("Unterminated regular expression", function(){
3665 var prev_backslash = false, ch, in_class = false;
3666 while ((ch = next(true))) if (prev_backslash) {
3667 regexp += "\\" + ch;
3668 prev_backslash = false;
3669 } else if (ch == "[") {
3672 } else if (ch == "]" && in_class) {
3675 } else if (ch == "/" && !in_class) {
3677 } else if (ch == "\\") {
3678 prev_backslash = true;
3682 var mods = read_name();
3683 return token("regexp", [ regexp, mods ]);
3687 function read_operator(prefix) {
3689 if (!peek()) return op;
3690 var bigger = op + peek();
3691 if (HOP(OPERATORS, bigger)) {
3693 return grow(bigger);
3698 return token("operator", grow(prefix || next()));
3701 function handle_slash() {
3703 var regex_allowed = S.regex_allowed;
3706 S.comments_before.push(read_line_comment());
3707 S.regex_allowed = regex_allowed;
3708 return next_token();
3710 S.comments_before.push(read_multiline_comment());
3711 S.regex_allowed = regex_allowed;
3712 return next_token();
3714 return S.regex_allowed ? read_regexp("") : read_operator("/");
3717 function handle_dot() {
3719 return is_digit(peek())
3721 : token("punc", ".");
3724 function read_word() {
3725 var word = read_name();
3726 return !HOP(KEYWORDS, word)
3727 ? token("name", word)
3728 : HOP(OPERATORS, word)
3729 ? token("operator", word)
3730 : HOP(KEYWORDS_ATOM, word)
3731 ? token("atom", word)
3732 : token("keyword", word);
3735 function with_eof_error(eof_error, cont) {
3739 if (ex === EX_EOF) parse_error(eof_error);
3744 function next_token(force_regexp) {
3745 if (force_regexp != null)
3746 return read_regexp(force_regexp);
3750 if (!ch) return token("eof");
3751 if (is_digit(ch)) return read_num();
3752 if (ch == '"' || ch == "'") return read_string();
3753 if (HOP(PUNC_CHARS, ch)) return token("punc", next());
3754 if (ch == ".") return handle_dot();
3755 if (ch == "/") return handle_slash();
3756 if (HOP(OPERATOR_CHARS, ch)) return read_operator();
3757 if (ch == "\\" || is_identifier_start(ch)) return read_word();
3758 parse_error("Unexpected character '" + ch + "'");
3761 next_token.context = function(nc) {
3770 /* -----[ Parser (constants) ]----- */
3772 var UNARY_PREFIX = array_to_hash([
3784 var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
3786 var ASSIGNMENT = (function(a, ret, i){
3787 while (i < a.length) {
3788 ret[a[i]] = a[i].substr(0, a[i].length - 1);
3793 ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
3798 var PRECEDENCE = (function(a, ret){
3799 for (var i = 0, n = 1; i < a.length; ++i, ++n) {
3801 for (var j = 0; j < b.length; ++j) {
3813 ["==", "===", "!=", "!=="],
3814 ["<", ">", "<=", ">=", "in", "instanceof"],
3815 [">>", "<<", ">>>"],
3822 var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
3824 var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
3826 /* -----[ Parser ]----- */
3828 function NodeWithToken(str, start, end) {
3834 NodeWithToken.prototype.toString = function() { return this.name; };
3836 function parse($TEXT, exigent_mode, embed_tokens) {
3839 input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
3850 function is(type, value) {
3851 return is_token(S.token, type, value);
3854 function peek() { return S.peeked || (S.peeked = S.input()); };
3862 S.token = S.input();
3871 function croak(msg, line, col, pos) {
3872 var ctx = S.input.context();
3874 line != null ? line : ctx.tokline,
3875 col != null ? col : ctx.tokcol,
3876 pos != null ? pos : ctx.tokpos);
3879 function token_error(token, msg) {
3880 croak(msg, token.line, token.col);
3883 function unexpected(token) {
3886 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
3889 function expect_token(type, val) {
3890 if (is(type, val)) {
3893 token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
3896 function expect(punc) { return expect_token("punc", punc); };
3898 function can_insert_semicolon() {
3899 return !exigent_mode && (
3900 S.token.nlb || is("eof") || is("punc", "}")
3904 function semicolon() {
3905 if (is("punc", ";")) next();
3906 else if (!can_insert_semicolon()) unexpected();
3910 return slice(arguments);
3913 function parenthesised() {
3915 var ex = expression();
3920 function add_tokens(str, start, end) {
3921 return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
3924 function maybe_embed_tokens(parser) {
3925 if (embed_tokens) return function() {
3926 var start = S.token;
3927 var ast = parser.apply(this, arguments);
3928 ast[0] = add_tokens(ast[0], start, prev());
3934 var statement = maybe_embed_tokens(function() {
3935 if (is("operator", "/") || is("operator", "/=")) {
3937 S.token = S.input(S.token.value.substr(1)); // force regexp
3939 switch (S.token.type) {
3945 return simple_statement();
3948 return is_token(peek(), "punc", ":")
3949 ? labeled_statement(prog1(S.token.value, next, next))
3950 : simple_statement();
3953 switch (S.token.value) {
3955 return as("block", block_());
3958 return simple_statement();
3967 switch (prog1(S.token.value, next)) {
3969 return break_cont("break");
3972 return break_cont("continue");
3976 return as("debugger");
3979 return (function(body){
3980 expect_token("keyword", "while");
3981 return as("do", prog1(parenthesised, semicolon), body);
3982 })(in_loop(statement));
3988 return function_(true);
3994 if (S.in_function == 0)
3995 croak("'return' outside of function");
3999 : can_insert_semicolon()
4001 : prog1(expression, semicolon));
4004 return as("switch", parenthesised(), switch_block_());
4008 croak("Illegal newline after 'throw'");
4009 return as("throw", prog1(expression, semicolon));
4015 return prog1(var_, semicolon);
4018 return prog1(const_, semicolon);
4021 return as("while", parenthesised(), in_loop(statement));
4024 return as("with", parenthesised(), statement());
4032 function labeled_statement(label) {
4033 S.labels.push(label);
4034 var start = S.token, stat = statement();
4035 if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
4038 return as("label", label, stat);
4041 function simple_statement() {
4042 return as("stat", prog1(expression, semicolon));
4045 function break_cont(type) {
4047 if (!can_insert_semicolon()) {
4048 name = is("name") ? S.token.value : null;
4052 if (!member(name, S.labels))
4053 croak("Label " + name + " without matching loop or statement");
4055 else if (S.in_loop == 0)
4056 croak(type + " not inside a loop or switch");
4058 return as(type, name);
4064 if (!is("punc", ";")) {
4065 init = is("keyword", "var")
4066 ? (next(), var_(true))
4067 : expression(true, true);
4068 if (is("operator", "in"))
4069 return for_in(init);
4071 return regular_for(init);
4074 function regular_for(init) {
4076 var test = is("punc", ";") ? null : expression();
4078 var step = is("punc", ")") ? null : expression();
4080 return as("for", init, test, step, in_loop(statement));
4083 function for_in(init) {
4084 var lhs = init[0] == "var" ? as("name", init[1][0]) : init;
4086 var obj = expression();
4088 return as("for-in", init, lhs, obj, in_loop(statement));
4091 var function_ = function(in_statement) {
4092 var name = is("name") ? prog1(S.token.value, next) : null;
4093 if (in_statement && !name)
4096 return as(in_statement ? "defun" : "function",
4099 (function(first, a){
4100 while (!is("punc", ")")) {
4101 if (first) first = false; else expect(",");
4102 if (!is("name")) unexpected();
4103 a.push(S.token.value);
4112 var loop = S.in_loop;
4122 var cond = parenthesised(), body = statement(), belse;
4123 if (is("keyword", "else")) {
4125 belse = statement();
4127 return as("if", cond, body, belse);
4133 while (!is("punc", "}")) {
4134 if (is("eof")) unexpected();
4135 a.push(statement());
4141 var switch_block_ = curry(in_loop, function(){
4143 var a = [], cur = null;
4144 while (!is("punc", "}")) {
4145 if (is("eof")) unexpected();
4146 if (is("keyword", "case")) {
4149 a.push([ expression(), cur ]);
4152 else if (is("keyword", "default")) {
4156 a.push([ null, cur ]);
4159 if (!cur) unexpected();
4160 cur.push(statement());
4168 var body = block_(), bcatch, bfinally;
4169 if (is("keyword", "catch")) {
4173 croak("Name expected");
4174 var name = S.token.value;
4177 bcatch = [ name, block_() ];
4179 if (is("keyword", "finally")) {
4181 bfinally = block_();
4183 if (!bcatch && !bfinally)
4184 croak("Missing catch/finally blocks");
4185 return as("try", body, bcatch, bfinally);
4188 function vardefs(no_in) {
4193 var name = S.token.value;
4195 if (is("operator", "=")) {
4197 a.push([ name, expression(false, no_in) ]);
4201 if (!is("punc", ","))
4208 function var_(no_in) {
4209 return as("var", vardefs(no_in));
4213 return as("const", vardefs());
4217 var newexp = expr_atom(false), args;
4218 if (is("punc", "(")) {
4220 args = expr_list(")");
4224 return subscripts(as("new", newexp, args), true);
4227 var expr_atom = maybe_embed_tokens(function(allow_calls) {
4228 if (is("operator", "new")) {
4233 switch (S.token.value) {
4236 return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
4239 return subscripts(array_(), allow_calls);
4242 return subscripts(object_(), allow_calls);
4246 if (is("keyword", "function")) {
4248 return subscripts(function_(false), allow_calls);
4250 if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
4251 var atom = S.token.type == "regexp"
4252 ? as("regexp", S.token.value[0], S.token.value[1])
4253 : as(S.token.type, S.token.value);
4254 return subscripts(prog1(atom, next), allow_calls);
4259 function expr_list(closing, allow_trailing_comma, allow_empty) {
4260 var first = true, a = [];
4261 while (!is("punc", closing)) {
4262 if (first) first = false; else expect(",");
4263 if (allow_trailing_comma && is("punc", closing)) break;
4264 if (is("punc", ",") && allow_empty) {
4265 a.push([ "atom", "undefined" ]);
4267 a.push(expression(false));
4275 return as("array", expr_list("]", !exigent_mode, true));
4278 function object_() {
4279 var first = true, a = [];
4280 while (!is("punc", "}")) {
4281 if (first) first = false; else expect(",");
4282 if (!exigent_mode && is("punc", "}"))
4283 // allow trailing comma
4285 var type = S.token.type;
4286 var name = as_property_name();
4287 if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
4288 a.push([ as_name(), function_(false), name ]);
4291 a.push([ name, expression(false) ]);
4295 return as("object", a);
4298 function as_property_name() {
4299 switch (S.token.type) {
4302 return prog1(S.token.value, next);
4307 function as_name() {
4308 switch (S.token.type) {
4313 return prog1(S.token.value, next);
4319 function subscripts(expr, allow_calls) {
4320 if (is("punc", ".")) {
4322 return subscripts(as("dot", expr, as_name()), allow_calls);
4324 if (is("punc", "[")) {
4326 return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
4328 if (allow_calls && is("punc", "(")) {
4330 return subscripts(as("call", expr, expr_list(")")), true);
4335 function maybe_unary(allow_calls) {
4336 if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
4337 return make_unary("unary-prefix",
4338 prog1(S.token.value, next),
4339 maybe_unary(allow_calls));
4341 var val = expr_atom(allow_calls);
4342 while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) {
4343 val = make_unary("unary-postfix", S.token.value, val);
4349 function make_unary(tag, op, expr) {
4350 if ((op == "++" || op == "--") && !is_assignable(expr))
4351 croak("Invalid use of " + op + " operator");
4352 return as(tag, op, expr);
4355 function expr_op(left, min_prec, no_in) {
4356 var op = is("operator") ? S.token.value : null;
4357 if (op && op == "in" && no_in) op = null;
4358 var prec = op != null ? PRECEDENCE[op] : null;
4359 if (prec != null && prec > min_prec) {
4361 var right = expr_op(maybe_unary(true), prec, no_in);
4362 return expr_op(as("binary", op, left, right), min_prec, no_in);
4367 function expr_ops(no_in) {
4368 return expr_op(maybe_unary(true), 0, no_in);
4371 function maybe_conditional(no_in) {
4372 var expr = expr_ops(no_in);
4373 if (is("operator", "?")) {
4375 var yes = expression(false);
4377 return as("conditional", expr, yes, expression(false, no_in));
4382 function is_assignable(expr) {
4383 if (!exigent_mode) return true;
4384 switch (expr[0]+"") {
4391 return expr[1] != "this";
4395 function maybe_assign(no_in) {
4396 var left = maybe_conditional(no_in), val = S.token.value;
4397 if (is("operator") && HOP(ASSIGNMENT, val)) {
4398 if (is_assignable(left)) {
4400 return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));
4402 croak("Invalid assignment");
4407 var expression = maybe_embed_tokens(function(commas, no_in) {
4408 if (arguments.length == 0)
4410 var expr = maybe_assign(no_in);
4411 if (commas && is("punc", ",")) {
4413 return as("seq", expr, expression(true, no_in));
4418 function in_loop(cont) {
4427 return as("toplevel", (function(a){
4429 a.push(statement());
4435 /* -----[ Utilities ]----- */
4438 var args = slice(arguments, 1);
4439 return function() { return f.apply(this, args.concat(slice(arguments))); };
4442 function prog1(ret) {
4443 if (ret instanceof Function)
4445 for (var i = 1, n = arguments.length; --n > 0; ++i)
4450 function array_to_hash(a) {
4452 for (var i = 0; i < a.length; ++i)
4457 function slice(a, start) {
4458 return Array.prototype.slice.call(a, start || 0);
4461 function characters(str) {
4462 return str.split("");
4465 function member(name, array) {
4466 for (var i = array.length; --i >= 0;)
4467 if (array[i] == name)
4472 function HOP(obj, prop) {
4473 return Object.prototype.hasOwnProperty.call(obj, prop);
4476 var warn = function() {};
4478 /* -----[ Exports ]----- */
4480 exports.tokenizer = tokenizer;
4481 exports.parse = parse;
4482 exports.slice = slice;
4483 exports.curry = curry;
4484 exports.member = member;
4485 exports.array_to_hash = array_to_hash;
4486 exports.PRECEDENCE = PRECEDENCE;
4487 exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
4488 exports.RESERVED_WORDS = RESERVED_WORDS;
4489 exports.KEYWORDS = KEYWORDS;
4490 exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
4491 exports.OPERATORS = OPERATORS;
4492 exports.is_alphanumeric_char = is_alphanumeric_char;
4493 exports.set_logger = function(logger) {
4498 define('uglifyjs/squeeze-more', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
4500 var jsp = require("./parse-js"),
4501 pro = require("./process"),
4503 member = jsp.member,
4506 PRECEDENCE = jsp.PRECEDENCE,
4507 OPERATORS = jsp.OPERATORS;
4509 function ast_squeeze_more(ast) {
4510 var w = pro.ast_walker(), walk = w.walk, scope;
4511 function with_scope(s, cont) {
4512 var save = scope, ret;
4518 function _lambda(name, args, body) {
4519 return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
4521 return w.with_walkers({
4522 "toplevel": function(body) {
4523 return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
4525 "function": _lambda,
4527 "new": function(ctor, args) {
4528 if (ctor[0] == "name") {
4529 if (ctor[1] == "Array" && !scope.has("Array")) {
4530 if (args.length != 1) {
4531 return [ "array", args ];
4533 return walk([ "call", [ "name", "Array" ], args ]);
4535 } else if (ctor[1] == "Object" && !scope.has("Object")) {
4537 return [ "object", [] ];
4539 return walk([ "call", [ "name", "Object" ], args ]);
4541 } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) {
4542 return walk([ "call", [ "name", ctor[1] ], args]);
4546 "call": function(expr, args) {
4547 if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
4548 // foo.toString() ==> foo+""
4549 return [ "binary", "+", expr[1], [ "string", "" ]];
4551 if (expr[0] == "name") {
4552 if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
4553 return [ "array", args ];
4555 if (expr[1] == "Object" && !args.length && !scope.has("Object")) {
4556 return [ "object", [] ];
4558 if (expr[1] == "String" && !scope.has("String")) {
4559 return [ "binary", "+", args[0], [ "string", "" ]];
4564 return walk(pro.ast_add_scope(ast));
4568 exports.ast_squeeze_more = ast_squeeze_more;
4570 });define('uglifyjs/process', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
4572 /***********************************************************************
4574 A JavaScript tokenizer / parser / beautifier / compressor.
4576 This version is suitable for Node.js. With minimal changes (the
4577 exports stuff) it should work on any JS platform.
4579 This file implements some AST processors. They work on data built
4584 - ast_mangle(ast, options) -- mangles the variable/function names
4585 in the AST. Returns an AST.
4587 - ast_squeeze(ast) -- employs various optimizations to make the
4588 final generated code even smaller. Returns an AST.
4590 - gen_code(ast, options) -- generates JS code from the AST. Pass
4591 true (or an object, see the code for some options) as second
4592 argument to get "pretty" (indented) code.
4594 -------------------------------- (C) ---------------------------------
4597 <mihai.bazon@gmail.com>
4598 http://mihai.bazon.net/blog
4600 Distributed under the BSD license:
4602 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
4604 Redistribution and use in source and binary forms, with or without
4605 modification, are permitted provided that the following conditions
4608 * Redistributions of source code must retain the above
4609 copyright notice, this list of conditions and the following
4612 * Redistributions in binary form must reproduce the above
4613 copyright notice, this list of conditions and the following
4614 disclaimer in the documentation and/or other materials
4615 provided with the distribution.
4617 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
4618 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4619 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4620 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
4621 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
4622 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
4623 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
4624 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4625 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
4626 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
4627 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4630 ***********************************************************************/
4632 var jsp = require("./parse-js"),
4634 member = jsp.member,
4635 PRECEDENCE = jsp.PRECEDENCE,
4636 OPERATORS = jsp.OPERATORS;
4638 /* -----[ helper for AST traversal ]----- */
4640 function ast_walker() {
4641 function _vardefs(defs) {
4642 return [ this[0], MAP(defs, function(def){
4645 a[1] = walk(def[1]);
4649 function _block(statements) {
4650 var out = [ this[0] ];
4651 if (statements != null)
4652 out.push(MAP(statements, walk));
4656 "string": function(str) {
4657 return [ this[0], str ];
4659 "num": function(num) {
4660 return [ this[0], num ];
4662 "name": function(name) {
4663 return [ this[0], name ];
4665 "toplevel": function(statements) {
4666 return [ this[0], MAP(statements, walk) ];
4672 "try": function(t, c, f) {
4676 c != null ? [ c[0], MAP(c[1], walk) ] : null,
4677 f != null ? MAP(f, walk) : null
4680 "throw": function(expr) {
4681 return [ this[0], walk(expr) ];
4683 "new": function(ctor, args) {
4684 return [ this[0], walk(ctor), MAP(args, walk) ];
4686 "switch": function(expr, body) {
4687 return [ this[0], walk(expr), MAP(body, function(branch){
4688 return [ branch[0] ? walk(branch[0]) : null,
4689 MAP(branch[1], walk) ];
4692 "break": function(label) {
4693 return [ this[0], label ];
4695 "continue": function(label) {
4696 return [ this[0], label ];
4698 "conditional": function(cond, t, e) {
4699 return [ this[0], walk(cond), walk(t), walk(e) ];
4701 "assign": function(op, lvalue, rvalue) {
4702 return [ this[0], op, walk(lvalue), walk(rvalue) ];
4704 "dot": function(expr) {
4705 return [ this[0], walk(expr) ].concat(slice(arguments, 1));
4707 "call": function(expr, args) {
4708 return [ this[0], walk(expr), MAP(args, walk) ];
4710 "function": function(name, args, body) {
4711 return [ this[0], name, args.slice(), MAP(body, walk) ];
4713 "defun": function(name, args, body) {
4714 return [ this[0], name, args.slice(), MAP(body, walk) ];
4716 "if": function(conditional, t, e) {
4717 return [ this[0], walk(conditional), walk(t), walk(e) ];
4719 "for": function(init, cond, step, block) {
4720 return [ this[0], walk(init), walk(cond), walk(step), walk(block) ];
4722 "for-in": function(vvar, key, hash, block) {
4723 return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ];
4725 "while": function(cond, block) {
4726 return [ this[0], walk(cond), walk(block) ];
4728 "do": function(cond, block) {
4729 return [ this[0], walk(cond), walk(block) ];
4731 "return": function(expr) {
4732 return [ this[0], walk(expr) ];
4734 "binary": function(op, left, right) {
4735 return [ this[0], op, walk(left), walk(right) ];
4737 "unary-prefix": function(op, expr) {
4738 return [ this[0], op, walk(expr) ];
4740 "unary-postfix": function(op, expr) {
4741 return [ this[0], op, walk(expr) ];
4743 "sub": function(expr, subscript) {
4744 return [ this[0], walk(expr), walk(subscript) ];
4746 "object": function(props) {
4747 return [ this[0], MAP(props, function(p){
4748 return p.length == 2
4749 ? [ p[0], walk(p[1]) ]
4750 : [ p[0], walk(p[1]), p[2] ]; // get/set-ter
4753 "regexp": function(rx, mods) {
4754 return [ this[0], rx, mods ];
4756 "array": function(elements) {
4757 return [ this[0], MAP(elements, walk) ];
4759 "stat": function(stat) {
4760 return [ this[0], walk(stat) ];
4763 return [ this[0] ].concat(MAP(slice(arguments), walk));
4765 "label": function(name, block) {
4766 return [ this[0], name, walk(block) ];
4768 "with": function(expr, block) {
4769 return [ this[0], walk(expr), walk(block) ];
4771 "atom": function(name) {
4772 return [ this[0], name ];
4778 function walk(ast) {
4784 var gen = user[type];
4786 var ret = gen.apply(ast, ast.slice(1));
4790 gen = walkers[type];
4791 return gen.apply(ast, ast.slice(1));
4797 function dive(ast) {
4802 return walkers[ast[0]].apply(ast, ast.slice(1));
4808 function with_walkers(walkers, cont){
4810 for (i in walkers) if (HOP(walkers, i)) {
4812 user[i] = walkers[i];
4815 for (i in save) if (HOP(save, i)) {
4816 if (!save[i]) delete user[i];
4817 else user[i] = save[i];
4825 with_walkers: with_walkers,
4826 parent: function() {
4827 return stack[stack.length - 2]; // last one is current node
4835 /* -----[ Scope and mangling ]----- */
4837 function Scope(parent) {
4838 this.names = {}; // names defined in this scope
4839 this.mangled = {}; // mangled names (orig.name => mangled)
4840 this.rev_mangled = {}; // reverse lookup (mangled => orig.name)
4841 this.cname = -1; // current mangled name
4842 this.refs = {}; // names referenced from this scope
4843 this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes
4844 this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes
4845 this.parent = parent; // parent scope
4846 this.children = []; // sub-scopes
4848 this.level = parent.level + 1;
4849 parent.children.push(this);
4855 var base54 = (function(){
4856 var DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
4857 return function(num) {
4860 ret = DIGITS.charAt(num % 54) + ret;
4861 num = Math.floor(num / 54);
4868 has: function(name) {
4869 for (var s = this; s; s = s.parent)
4870 if (HOP(s.names, name))
4873 has_mangled: function(mname) {
4874 for (var s = this; s; s = s.parent)
4875 if (HOP(s.rev_mangled, mname))
4878 toJSON: function() {
4881 uses_eval: this.uses_eval,
4882 uses_with: this.uses_with
4886 next_mangled: function() {
4887 // we must be careful that the new mangled name:
4889 // 1. doesn't shadow a mangled name from a parent
4890 // scope, unless we don't reference the original
4891 // name from this scope OR from any sub-scopes!
4892 // This will get slow.
4894 // 2. doesn't shadow an original name from a parent
4895 // scope, in the event that the name is not mangled
4896 // in the parent scope and we reference that name
4897 // here OR IN ANY SUBSCOPES!
4899 // 3. doesn't shadow a name that is referenced but not
4900 // defined (possibly global defined elsewhere).
4902 var m = base54(++this.cname), prior;
4905 prior = this.has_mangled(m);
4906 if (prior && this.refs[prior.rev_mangled[m]] === prior)
4910 prior = this.has(m);
4911 if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m))
4915 if (HOP(this.refs, m) && this.refs[m] == null)
4918 // I got "do" once. :-/
4919 if (!is_identifier(m))
4925 set_mangle: function(name, m) {
4926 this.rev_mangled[m] = name;
4927 return this.mangled[name] = m;
4929 get_mangled: function(name, newMangle) {
4930 if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use
4931 var s = this.has(name);
4932 if (!s) return name; // not in visible scope, no mangle
4933 if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope
4934 if (!newMangle) return name; // not found and no mangling requested
4935 return s.set_mangle(name, s.next_mangled());
4937 references: function(name) {
4938 return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name];
4940 define: function(name, type) {
4942 if (type == "var" || !HOP(this.names, name))
4943 this.names[name] = type || "var";
4949 function ast_add_scope(ast) {
4951 var current_scope = null;
4952 var w = ast_walker(), walk = w.walk;
4953 var having_eval = [];
4955 function with_new_scope(cont) {
4956 current_scope = new Scope(current_scope);
4957 current_scope.labels = new Scope();
4958 var ret = current_scope.body = cont();
4959 ret.scope = current_scope;
4960 current_scope = current_scope.parent;
4964 function define(name, type) {
4965 return current_scope.define(name, type);
4968 function reference(name) {
4969 current_scope.refs[name] = true;
4972 function _lambda(name, args, body) {
4973 var is_defun = this[0] == "defun";
4974 return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){
4975 if (!is_defun) define(name, "lambda");
4976 MAP(args, function(name){ define(name, "arg") });
4977 return MAP(body, walk);
4981 function _vardefs(type) {
4982 return function(defs) {
4983 MAP(defs, function(d){
4985 if (d[1]) reference(d[0]);
4990 function _breacont(label) {
4992 current_scope.labels.refs[label] = true;
4995 return with_new_scope(function(){
4997 var ret = w.with_walkers({
4998 "function": _lambda,
5000 "label": function(name, stat) { current_scope.labels.define(name) },
5002 "continue": _breacont,
5003 "with": function(expr, block) {
5004 for (var s = current_scope; s; s = s.parent)
5007 "var": _vardefs("var"),
5008 "const": _vardefs("const"),
5009 "try": function(t, c, f) {
5010 if (c != null) return [
5013 [ define(c[0], "catch"), MAP(c[1], walk) ],
5014 f != null ? MAP(f, walk) : null
5017 "name": function(name) {
5019 having_eval.push(current_scope);
5026 // the reason why we need an additional pass here is
5027 // that names can be used prior to their definition.
5029 // scopes where eval was detected and their parents
5030 // are marked with uses_eval, unless they define the
5032 MAP(having_eval, function(scope){
5033 if (!scope.has("eval")) while (scope) {
5034 scope.uses_eval = true;
5035 scope = scope.parent;
5039 // for referenced names it might be useful to know
5040 // their origin scope. current_scope here is the
5042 function fixrefs(scope, i) {
5043 // do children first; order shouldn't matter
5044 for (i = scope.children.length; --i >= 0;)
5045 fixrefs(scope.children[i]);
5046 for (i in scope.refs) if (HOP(scope.refs, i)) {
5047 // find origin scope and propagate the reference to origin
5048 for (var origin = scope.has(i), s = scope; s; s = s.parent) {
5050 if (s === origin) break;
5054 fixrefs(current_scope);
5061 /* -----[ mangle names ]----- */
5063 function ast_mangle(ast, options) {
5064 var w = ast_walker(), walk = w.walk, scope;
5065 options = options || {};
5067 function get_mangled(name, newMangle) {
5068 if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel
5069 if (options.except && member(name, options.except))
5071 return scope.get_mangled(name, newMangle);
5074 function get_define(name) {
5075 if (options.defines) {
5076 // we always lookup a defined symbol for the current scope FIRST, so declared
5077 // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value
5078 if (!scope.has(name)) {
5079 if (HOP(options.defines, name)) {
5080 return options.defines[name];
5087 function _lambda(name, args, body) {
5088 if (!options.no_functions) {
5089 var is_defun = this[0] == "defun", extra;
5091 if (is_defun) name = get_mangled(name);
5092 else if (body.scope.references(name)) {
5094 if (!(scope.uses_eval || scope.uses_with))
5095 name = extra[name] = scope.next_mangled();
5102 body = with_scope(body.scope, function(){
5103 args = MAP(args, function(name){ return get_mangled(name) });
5104 return MAP(body, walk);
5106 return [ this[0], name, args, body ];
5109 function with_scope(s, cont, extra) {
5112 if (extra) for (var i in extra) if (HOP(extra, i)) {
5113 s.set_mangle(i, extra[i]);
5115 for (var i in s.names) if (HOP(s.names, i)) {
5116 get_mangled(i, true);
5124 function _vardefs(defs) {
5125 return [ this[0], MAP(defs, function(d){
5126 return [ get_mangled(d[0]), walk(d[1]) ];
5130 function _breacont(label) {
5131 if (label) return [ this[0], scope.labels.get_mangled(label) ];
5134 return w.with_walkers({
5135 "function": _lambda,
5136 "defun": function() {
5137 // move function declarations to the top when
5138 // they are not in some block.
5139 var ast = _lambda.apply(this, arguments);
5140 switch (w.parent()[0]) {
5144 return MAP.at_top(ast);
5148 "label": function(label, stat) {
5149 if (scope.labels.refs[label]) return [
5151 scope.labels.get_mangled(label, true),
5157 "continue": _breacont,
5160 "name": function(name) {
5161 return get_define(name) || [ this[0], get_mangled(name) ];
5163 "try": function(t, c, f) {
5166 c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null,
5167 f != null ? MAP(f, walk) : null ];
5169 "toplevel": function(body) {
5171 return with_scope(self.scope, function(){
5172 return [ self[0], MAP(body, walk) ];
5176 return walk(ast_add_scope(ast));
5181 - compress foo["bar"] into foo.bar,
5182 - remove block brackets {} where possible
5183 - join consecutive var declarations
5184 - various optimizations for IFs:
5185 - if (cond) foo(); else bar(); ==> cond?foo():bar();
5186 - if (cond) foo(); ==> cond&&foo();
5187 - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); // also for throw
5188 - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
5191 var warn = function(){};
5193 function best_of(ast1, ast2) {
5194 return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
5197 function last_stat(b) {
5198 if (b[0] == "block" && b[1] && b[1].length > 0)
5199 return b[1][b[1].length - 1];
5203 function aborts(t) {
5204 if (t) switch (last_stat(t)[0]) {
5213 function boolean_expr(expr) {
5214 return ( (expr[0] == "unary-prefix"
5215 && member(expr[1], [ "!", "delete" ])) ||
5217 (expr[0] == "binary"
5218 && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) ||
5220 (expr[0] == "binary"
5221 && member(expr[1], [ "&&", "||" ])
5222 && boolean_expr(expr[2])
5223 && boolean_expr(expr[3])) ||
5225 (expr[0] == "conditional"
5226 && boolean_expr(expr[2])
5227 && boolean_expr(expr[3])) ||
5229 (expr[0] == "assign"
5231 && boolean_expr(expr[3])) ||
5234 && boolean_expr(expr[expr.length - 1]))
5239 return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
5242 function is_string(node) {
5243 return (node[0] == "string" ||
5244 node[0] == "unary-prefix" && node[1] == "typeof" ||
5245 node[0] == "binary" && node[1] == "+" &&
5246 (is_string(node[2]) || is_string(node[3])));
5249 var when_constant = (function(){
5251 var $NOT_CONSTANT = {};
5253 // this can only evaluate constant expressions. If it finds anything
5254 // not constant, it throws $NOT_CONSTANT.
5255 function evaluate(expr) {
5263 case "true": return true;
5264 case "false": return false;
5265 case "null": return null;
5268 case "unary-prefix":
5270 case "!": return !evaluate(expr[2]);
5271 case "typeof": return typeof evaluate(expr[2]);
5272 case "~": return ~evaluate(expr[2]);
5273 case "-": return -evaluate(expr[2]);
5274 case "+": return +evaluate(expr[2]);
5278 var left = expr[2], right = expr[3];
5280 case "&&" : return evaluate(left) && evaluate(right);
5281 case "||" : return evaluate(left) || evaluate(right);
5282 case "|" : return evaluate(left) | evaluate(right);
5283 case "&" : return evaluate(left) & evaluate(right);
5284 case "^" : return evaluate(left) ^ evaluate(right);
5285 case "+" : return evaluate(left) + evaluate(right);
5286 case "*" : return evaluate(left) * evaluate(right);
5287 case "/" : return evaluate(left) / evaluate(right);
5288 case "%" : return evaluate(left) % evaluate(right);
5289 case "-" : return evaluate(left) - evaluate(right);
5290 case "<<" : return evaluate(left) << evaluate(right);
5291 case ">>" : return evaluate(left) >> evaluate(right);
5292 case ">>>" : return evaluate(left) >>> evaluate(right);
5293 case "==" : return evaluate(left) == evaluate(right);
5294 case "===" : return evaluate(left) === evaluate(right);
5295 case "!=" : return evaluate(left) != evaluate(right);
5296 case "!==" : return evaluate(left) !== evaluate(right);
5297 case "<" : return evaluate(left) < evaluate(right);
5298 case "<=" : return evaluate(left) <= evaluate(right);
5299 case ">" : return evaluate(left) > evaluate(right);
5300 case ">=" : return evaluate(left) >= evaluate(right);
5301 case "in" : return evaluate(left) in evaluate(right);
5302 case "instanceof" : return evaluate(left) instanceof evaluate(right);
5305 throw $NOT_CONSTANT;
5308 return function(expr, yes, no) {
5310 var val = evaluate(expr), ast;
5311 switch (typeof val) {
5312 case "string": ast = [ "string", val ]; break;
5313 case "number": ast = [ "num", val ]; break;
5314 case "boolean": ast = [ "name", String(val) ]; break;
5315 default: throw new Error("Can't handle constant of type: " + (typeof val));
5317 return yes.call(expr, ast, val);
5319 if (ex === $NOT_CONSTANT) {
5320 if (expr[0] == "binary"
5321 && (expr[1] == "===" || expr[1] == "!==")
5322 && ((is_string(expr[2]) && is_string(expr[3]))
5323 || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) {
5324 expr[1] = expr[1].substr(0, 2);
5326 else if (no && expr[0] == "binary"
5327 && (expr[1] == "||" || expr[1] == "&&")) {
5328 // the whole expression is not constant but the lval may be...
5330 var lval = evaluate(expr[2]);
5331 expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) ||
5332 (expr[1] == "||" && (lval ? lval : expr[3])) ||
5335 // IGNORE... lval is not constant
5338 return no ? no.call(expr, expr) : null;
5346 function warn_unreachable(ast) {
5348 warn("Dropping unreachable code: " + gen_code(ast, true));
5351 function prepare_ifs(ast) {
5352 var w = ast_walker(), walk = w.walk;
5353 // In this first pass, we rewrite ifs which abort with no else with an
5354 // if-else. For example:
5362 // is rewritten into:
5370 function redo_if(statements) {
5371 statements = MAP(statements, walk);
5373 for (var i = 0; i < statements.length; ++i) {
5374 var fi = statements[i];
5375 if (fi[0] != "if") continue;
5377 if (fi[3] && walk(fi[3])) continue;
5379 var t = walk(fi[2]);
5380 if (!aborts(t)) continue;
5382 var conditional = walk(fi[1]);
5384 var e_body = statements.slice(i + 1);
5385 var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ];
5387 var ret = statements.slice(0, i).concat([ [
5389 conditional, // conditional
5394 return redo_if(ret);
5400 function redo_if_lambda(name, args, body) {
5401 body = redo_if(body);
5402 return [ this[0], name, args, body ];
5405 function redo_if_block(statements) {
5406 return [ this[0], statements != null ? redo_if(statements) : null ];
5409 return w.with_walkers({
5410 "defun": redo_if_lambda,
5411 "function": redo_if_lambda,
5412 "block": redo_if_block,
5413 "splice": redo_if_block,
5414 "toplevel": function(statements) {
5415 return [ this[0], redo_if(statements) ];
5417 "try": function(t, c, f) {
5421 c != null ? [ c[0], redo_if(c[1]) ] : null,
5422 f != null ? redo_if(f) : null
5430 function for_side_effects(ast, handler) {
5431 var w = ast_walker(), walk = w.walk;
5432 var $stop = {}, $restart = {};
5433 function stop() { throw $stop };
5434 function restart() { throw $restart };
5435 function found(){ return handler.call(this, this, w, stop, restart) };
5436 function unary(op) {
5437 if (op == "++" || op == "--")
5438 return found.apply(this, arguments);
5440 return w.with_walkers({
5456 "unary-prefix": unary,
5457 "unary-postfix": unary,
5464 if (ex === $stop) break;
5465 if (ex === $restart) continue;
5471 function ast_lift_variables(ast) {
5472 var w = ast_walker(), walk = w.walk, scope;
5473 function do_body(body, env) {
5476 body = MAP(body, walk);
5477 var hash = {}, names = MAP(env.names, function(type, name){
5478 if (type != "var") return MAP.skip;
5479 if (!env.references(name)) return MAP.skip;
5483 if (names.length > 0) {
5484 // looking for assignments to any of these variables.
5485 // we can save considerable space by moving the definitions
5486 // in the var declaration.
5487 for_side_effects([ "block", body ], function(ast, walker, stop, restart) {
5488 if (ast[0] == "assign"
5490 && ast[2][0] == "name"
5491 && HOP(hash, ast[2][1])) {
5492 // insert the definition into the var declaration
5493 for (var i = names.length; --i >= 0;) {
5494 if (names[i][0] == ast[2][1]) {
5495 if (names[i][1]) // this name already defined, we must stop
5497 names[i][1] = ast[3]; // definition
5498 names.push(names.splice(i, 1)[0]);
5502 // remove this assignment from the AST.
5503 var p = walker.parent();
5504 if (p[0] == "seq") {
5506 a.unshift(0, p.length);
5507 p.splice.apply(p, a);
5509 else if (p[0] == "stat") {
5510 p.splice(0, p.length, "block"); // empty statement
5519 body.unshift([ "var", names ]);
5524 function _vardefs(defs) {
5526 for (var i = defs.length; --i >= 0;) {
5528 if (!d[1]) continue;
5529 d = [ "assign", true, [ "name", d[0] ], d[1] ];
5530 if (ret == null) ret = d;
5531 else ret = [ "seq", d, ret ];
5534 if (w.parent()[0] == "for-in")
5535 return [ "name", defs[0][0] ];
5538 return [ "stat", ret ];
5540 function _toplevel(body) {
5541 return [ this[0], do_body(body, this.scope) ];
5543 return w.with_walkers({
5544 "function": function(name, args, body){
5545 for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
5547 if (!body.scope.references(name)) name = null;
5548 return [ this[0], name, args, do_body(body, body.scope) ];
5550 "defun": function(name, args, body){
5551 if (!scope.references(name)) return MAP.skip;
5552 for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
5554 return [ this[0], name, args, do_body(body, body.scope) ];
5557 "toplevel": _toplevel
5559 return walk(ast_add_scope(ast));
5563 function ast_squeeze(ast, options) {
5564 options = defaults(options, {
5567 no_warnings : false,
5571 var w = ast_walker(), walk = w.walk;
5573 function negate(c) {
5574 var not_c = [ "unary-prefix", "!", c ];
5576 case "unary-prefix":
5577 return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c;
5580 c[c.length - 1] = negate(c[c.length - 1]);
5583 return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]);
5585 var op = c[1], left = c[2], right = c[3];
5586 if (!options.keep_comps) switch (op) {
5587 case "<=" : return [ "binary", ">", left, right ];
5588 case "<" : return [ "binary", ">=", left, right ];
5589 case ">=" : return [ "binary", "<", left, right ];
5590 case ">" : return [ "binary", "<=", left, right ];
5593 case "==" : return [ "binary", "!=", left, right ];
5594 case "!=" : return [ "binary", "==", left, right ];
5595 case "===" : return [ "binary", "!==", left, right ];
5596 case "!==" : return [ "binary", "===", left, right ];
5597 case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]);
5598 case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]);
5605 function make_conditional(c, t, e) {
5606 var make_real_conditional = function() {
5607 if (c[0] == "unary-prefix" && c[1] == "!") {
5608 return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
5611 [ "conditional", c, t, e ],
5612 [ "conditional", negate(c), e, t ]
5613 ) : [ "binary", "&&", c, t ];
5616 // shortcut the conditional if the expression has a constant value
5617 return when_constant(c, function(ast, val){
5618 warn_unreachable(val ? e : t);
5619 return (val ? t : e);
5620 }, make_real_conditional);
5623 function rmblock(block) {
5624 if (block != null && block[0] == "block" && block[1]) {
5625 if (block[1].length == 1)
5626 block = block[1][0];
5627 else if (block[1].length == 0)
5628 block = [ "block" ];
5633 function _lambda(name, args, body) {
5634 return [ this[0], name, args, tighten(body, "lambda") ];
5637 // this function does a few things:
5638 // 1. discard useless blocks
5639 // 2. join consecutive var declarations
5640 // 3. remove obviously dead code
5641 // 4. transform consecutive statements using the comma operator
5642 // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... }
5643 function tighten(statements, block_type) {
5644 statements = MAP(statements, walk);
5646 statements = statements.reduce(function(a, stat){
5647 if (stat[0] == "block") {
5649 a.push.apply(a, stat[1]);
5657 statements = (function(a, prev){
5658 statements.forEach(function(cur){
5659 if (prev && ((cur[0] == "var" && prev[0] == "var") ||
5660 (cur[0] == "const" && prev[0] == "const"))) {
5661 prev[1] = prev[1].concat(cur[1]);
5670 if (options.dead_code) statements = (function(a, has_quit){
5671 statements.forEach(function(st){
5673 if (st[0] == "function" || st[0] == "defun") {
5676 else if (st[0] == "var" || st[0] == "const") {
5677 if (!options.no_warnings)
5678 warn("Variables declared in unreachable code");
5679 st[1] = MAP(st[1], function(def){
5680 if (def[1] && !options.no_warnings)
5681 warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]);
5686 else if (!options.no_warnings)
5687 warn_unreachable(st);
5691 if (member(st[0], [ "return", "throw", "break", "continue" ]))
5698 if (options.make_seqs) statements = (function(a, prev) {
5699 statements.forEach(function(cur){
5700 if (prev && prev[0] == "stat" && cur[0] == "stat") {
5701 prev[1] = [ "seq", prev[1], cur[1] ];
5708 && a[a.length-2][0] == "stat"
5709 && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw")
5710 && a[a.length-1][1])
5712 a.splice(a.length - 2, 2,
5714 [ "seq", a[a.length-2][1], a[a.length-1][1] ]]);
5719 // this increases jQuery by 1K. Probably not such a good idea after all..
5720 // part of this is done in prepare_ifs anyway.
5721 // if (block_type == "lambda") statements = (function(i, a, stat){
5722 // while (i < statements.length) {
5723 // stat = statements[i++];
5724 // if (stat[0] == "if" && !stat[3]) {
5725 // if (stat[2][0] == "return" && stat[2][1] == null) {
5726 // a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
5729 // var last = last_stat(stat[2]);
5730 // if (last[0] == "return" && last[1] == null) {
5731 // a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
5743 function make_if(c, t, e) {
5744 return when_constant(c, function(ast, val){
5747 warn_unreachable(e);
5748 return t || [ "block" ];
5751 warn_unreachable(t);
5752 return e || [ "block" ];
5755 return make_real_if(c, t, e);
5759 function make_real_if(c, t, e) {
5768 } else if (empty(e)) {
5771 // if we have both else and then, maybe it makes sense to switch them?
5773 var a = gen_code(c);
5775 var b = gen_code(n);
5776 if (b.length < a.length) {
5784 if (empty(e) && empty(t))
5785 return [ "stat", c ];
5786 var ret = [ "if", c, t, e ];
5787 if (t[0] == "if" && empty(t[3]) && empty(e)) {
5788 ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ]));
5790 else if (t[0] == "stat") {
5792 if (e[0] == "stat") {
5793 ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]);
5797 ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]);
5800 else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) {
5801 ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]);
5803 else if (e && aborts(t)) {
5804 ret = [ [ "if", c, t ] ];
5805 if (e[0] == "block") {
5806 if (e[1]) ret = ret.concat(e[1]);
5811 ret = walk([ "block", ret ]);
5813 else if (t && aborts(e)) {
5814 ret = [ [ "if", negate(c), e ] ];
5815 if (t[0] == "block") {
5816 if (t[1]) ret = ret.concat(t[1]);
5820 ret = walk([ "block", ret ]);
5825 function _do_while(cond, body) {
5826 return when_constant(cond, function(cond, val){
5828 warn_unreachable(body);
5831 return [ "for", null, null, null, walk(body) ];
5836 return w.with_walkers({
5837 "sub": function(expr, subscript) {
5838 if (subscript[0] == "string") {
5839 var name = subscript[1];
5840 if (is_identifier(name))
5841 return [ "dot", walk(expr), name ];
5842 else if (/^[1-9][0-9]*$/.test(name) || name === "0")
5843 return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ];
5847 "toplevel": function(body) {
5848 return [ "toplevel", tighten(body) ];
5850 "switch": function(expr, body) {
5851 var last = body.length - 1;
5852 return [ "switch", walk(expr), MAP(body, function(branch, i){
5853 var block = tighten(branch[1]);
5854 if (i == last && block.length > 0) {
5855 var node = block[block.length - 1];
5856 if (node[0] == "break" && !node[1])
5859 return [ branch[0] ? walk(branch[0]) : null, block ];
5862 "function": _lambda,
5864 "block": function(body) {
5865 if (body) return rmblock([ "block", tighten(body) ]);
5867 "binary": function(op, left, right) {
5868 return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){
5869 return best_of(walk(c), this);
5872 if(op != "==" && op != "!=") return;
5873 var l = walk(left), r = walk(right);
5874 if(l && l[0] == "unary-prefix" && l[1] == "!" && l[2][0] == "num")
5875 left = ['num', +!l[2][1]];
5876 else if (r && r[0] == "unary-prefix" && r[1] == "!" && r[2][0] == "num")
5877 right = ['num', +!r[2][1]];
5878 return ["binary", op, left, right];
5882 "conditional": function(c, t, e) {
5883 return make_conditional(walk(c), walk(t), walk(e));
5885 "try": function(t, c, f) {
5889 c != null ? [ c[0], tighten(c[1]) ] : null,
5890 f != null ? tighten(f) : null
5893 "unary-prefix": function(op, expr) {
5895 var ret = [ "unary-prefix", op, expr ];
5897 ret = best_of(ret, negate(expr));
5898 return when_constant(ret, function(ast, val){
5899 return walk(ast); // it's either true or false, so minifies to !0 or !1
5900 }, function() { return ret });
5902 "name": function(name) {
5904 case "true": return [ "unary-prefix", "!", [ "num", 0 ]];
5905 case "false": return [ "unary-prefix", "!", [ "num", 1 ]];
5909 "assign": function(op, lvalue, rvalue) {
5910 lvalue = walk(lvalue);
5911 rvalue = walk(rvalue);
5912 var okOps = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
5913 if (op === true && lvalue[0] === "name" && rvalue[0] === "binary" &&
5914 ~okOps.indexOf(rvalue[1]) && rvalue[2][0] === "name" &&
5915 rvalue[2][1] === lvalue[1]) {
5916 return [ this[0], rvalue[1], lvalue, rvalue[3] ]
5918 return [ this[0], op, lvalue, rvalue ];
5921 for (var i = 0; i < 2; ++i) {
5922 ast = prepare_ifs(ast);
5929 /* -----[ re-generate code from the AST ]----- */
5931 var DOT_CALL_NO_PARENS = jsp.array_to_hash([
5943 function make_string(str, ascii_only) {
5945 str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
5947 case "\\": return "\\\\";
5948 case "\b": return "\\b";
5949 case "\f": return "\\f";
5950 case "\n": return "\\n";
5951 case "\r": return "\\r";
5952 case "\t": return "\\t";
5953 case "\u2028": return "\\u2028";
5954 case "\u2029": return "\\u2029";
5955 case '"': ++dq; return '"';
5956 case "'": ++sq; return "'";
5957 case "\0": return "\\0";
5961 if (ascii_only) str = to_ascii(str);
5962 if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
5963 else return '"' + str.replace(/\x22/g, '\\"') + '"';
5966 function to_ascii(str) {
5967 return str.replace(/[\u0080-\uffff]/g, function(ch) {
5968 var code = ch.charCodeAt(0).toString(16);
5969 while (code.length < 4) code = "0" + code;
5970 return "\\u" + code;
5974 var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]);
5976 function gen_code(ast, options) {
5977 options = defaults(options, {
5981 space_colon : false,
5984 inline_script: false
5986 var beautify = !!options.beautify;
5987 var indentation = 0,
5988 newline = beautify ? "\n" : "",
5989 space = beautify ? " " : "";
5991 function encode_string(str) {
5992 var ret = make_string(str, options.ascii_only);
5993 if (options.inline_script)
5994 ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
5998 function make_name(name) {
5999 name = name.toString();
6000 if (options.ascii_only)
6001 name = to_ascii(name);
6005 function indent(line) {
6009 line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line;
6013 function with_indent(cont, incr) {
6014 if (incr == null) incr = 1;
6015 indentation += incr;
6016 try { return cont.apply(null, slice(arguments, 1)); }
6017 finally { indentation -= incr; }
6020 function add_spaces(a) {
6024 for (var i = 0; i < a.length; ++i) {
6025 var next = a[i + 1];
6028 ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) ||
6029 (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) {
6036 function add_commas(a) {
6037 return a.join("," + space);
6040 function parenthesize(expr) {
6041 var gen = make(expr);
6042 for (var i = 1; i < arguments.length; ++i) {
6043 var el = arguments[i];
6044 if ((el instanceof Function && el(expr)) || expr[0] == el)
6045 return "(" + gen + ")";
6050 function best_of(a) {
6051 if (a.length == 1) {
6054 if (a.length == 2) {
6057 return a.length <= b.length ? a : b;
6059 return best_of([ a[0], best_of(a.slice(1)) ]);
6062 function needs_parens(expr) {
6063 if (expr[0] == "function" || expr[0] == "object") {
6064 // dot/call on a literal function requires the
6065 // function literal itself to be parenthesized
6066 // only if it's the first "thing" in a
6067 // statement. This means that the parent is
6068 // "stat", but it could also be a "seq" and
6069 // we're the first in this "seq" and the
6070 // parent is "stat", and so on. Messy stuff,
6071 // but it worths the trouble.
6072 var a = slice(w.stack()), self = a.pop(), p = a.pop();
6074 if (p[0] == "stat") return true;
6075 if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) ||
6076 ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) {
6084 return !HOP(DOT_CALL_NO_PARENS, expr[0]);
6087 function make_num(num) {
6088 var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m;
6089 if (Math.floor(num) === num) {
6091 a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
6092 "0" + num.toString(8)); // same.
6094 a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
6095 "-0" + (-num).toString(8)); // same.
6097 if ((m = /^(.*?)(0+)$/.exec(num))) {
6098 a.push(m[1] + "e" + m[2].length);
6100 } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
6101 a.push(m[2] + "e-" + (m[1].length + m[2].length),
6102 str.substr(str.indexOf(".")));
6107 var w = ast_walker();
6109 return w.with_walkers({
6110 "string": encode_string,
6113 "toplevel": function(statements) {
6114 return make_block_statements(statements)
6115 .join(newline + newline);
6117 "splice": function(statements) {
6118 var parent = w.parent();
6119 if (HOP(SPLICE_NEEDS_BRACKETS, parent)) {
6120 // we need block brackets in this case
6121 return make_block.apply(this, arguments);
6123 return MAP(make_block_statements(statements, true),
6125 // the first line is already indented
6126 return i > 0 ? indent(line) : line;
6130 "block": make_block,
6131 "var": function(defs) {
6132 return "var " + add_commas(MAP(defs, make_1vardef)) + ";";
6134 "const": function(defs) {
6135 return "const " + add_commas(MAP(defs, make_1vardef)) + ";";
6137 "try": function(tr, ca, fi) {
6138 var out = [ "try", make_block(tr) ];
6139 if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1]));
6140 if (fi) out.push("finally", make_block(fi));
6141 return add_spaces(out);
6143 "throw": function(expr) {
6144 return add_spaces([ "throw", make(expr) ]) + ";";
6146 "new": function(ctor, args) {
6147 args = args.length > 0 ? "(" + add_commas(MAP(args, function(expr){
6148 return parenthesize(expr, "seq");
6150 return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){
6151 var w = ast_walker(), has_call = {};
6154 "call": function() { throw has_call },
6155 "function": function() { return this }
6160 if (ex === has_call)
6166 "switch": function(expr, body) {
6167 return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]);
6169 "break": function(label) {
6172 out += " " + make_name(label);
6175 "continue": function(label) {
6176 var out = "continue";
6178 out += " " + make_name(label);
6181 "conditional": function(co, th, el) {
6182 return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?",
6183 parenthesize(th, "seq"), ":",
6184 parenthesize(el, "seq") ]);
6186 "assign": function(op, lvalue, rvalue) {
6187 if (op && op !== true) op += "=";
6189 return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]);
6191 "dot": function(expr) {
6192 var out = make(expr), i = 1;
6193 if (expr[0] == "num") {
6194 if (!/\./.test(expr[1]))
6196 } else if (needs_parens(expr))
6197 out = "(" + out + ")";
6198 while (i < arguments.length)
6199 out += "." + make_name(arguments[i++]);
6202 "call": function(func, args) {
6204 if (f.charAt(0) != "(" && needs_parens(func))
6206 return f + "(" + add_commas(MAP(args, function(expr){
6207 return parenthesize(expr, "seq");
6210 "function": make_function,
6211 "defun": make_function,
6212 "if": function(co, th, el) {
6213 var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ];
6215 out.push("else", make(el));
6217 return add_spaces(out);
6219 "for": function(init, cond, step, block) {
6220 var out = [ "for" ];
6221 init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space);
6222 cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space);
6223 step = (step != null ? make(step) : "").replace(/;*\s*$/, "");
6224 var args = init + cond + step;
6225 if (args == "; ; ") args = ";;";
6226 out.push("(" + args + ")", make(block));
6227 return add_spaces(out);
6229 "for-in": function(vvar, key, hash, block) {
6230 return add_spaces([ "for", "(" +
6231 (vvar ? make(vvar).replace(/;+$/, "") : make(key)),
6233 make(hash) + ")", make(block) ]);
6235 "while": function(condition, block) {
6236 return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]);
6238 "do": function(condition, block) {
6239 return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";";
6241 "return": function(expr) {
6242 var out = [ "return" ];
6243 if (expr != null) out.push(make(expr));
6244 return add_spaces(out) + ";";
6246 "binary": function(operator, lvalue, rvalue) {
6247 var left = make(lvalue), right = make(rvalue);
6248 // XXX: I'm pretty sure other cases will bite here.
6249 // we need to be smarter.
6250 // adding parens all the time is the safest bet.
6251 if (member(lvalue[0], [ "assign", "conditional", "seq" ]) ||
6252 lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]] ||
6253 lvalue[0] == "function" && needs_parens(this)) {
6254 left = "(" + left + ")";
6256 if (member(rvalue[0], [ "assign", "conditional", "seq" ]) ||
6257 rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] &&
6258 !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) {
6259 right = "(" + right + ")";
6261 else if (!beautify && options.inline_script && (operator == "<" || operator == "<<")
6262 && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) {
6263 right = " " + right;
6265 return add_spaces([ left, operator, right ]);
6267 "unary-prefix": function(operator, expr) {
6268 var val = make(expr);
6269 if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
6270 val = "(" + val + ")";
6271 return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val;
6273 "unary-postfix": function(operator, expr) {
6274 var val = make(expr);
6275 if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
6276 val = "(" + val + ")";
6277 return val + operator;
6279 "sub": function(expr, subscript) {
6280 var hash = make(expr);
6281 if (needs_parens(expr))
6282 hash = "(" + hash + ")";
6283 return hash + "[" + make(subscript) + "]";
6285 "object": function(props) {
6286 var obj_needs_parens = needs_parens(this);
6287 if (props.length == 0)
6288 return obj_needs_parens ? "({})" : "{}";
6289 var out = "{" + newline + with_indent(function(){
6290 return MAP(props, function(p){
6291 if (p.length == 3) {
6292 // getter/setter. The name is in p[0], the arg.list in p[1][2], the
6293 // body in p[1][3] and type ("get" / "set") in p[2].
6294 return indent(make_function(p[0], p[1][2], p[1][3], p[2]));
6296 var key = p[0], val = parenthesize(p[1], "seq");
6297 if (options.quote_keys) {
6298 key = encode_string(key);
6299 } else if ((typeof key == "number" || !beautify && +key + "" == key)
6300 && parseFloat(key) >= 0) {
6301 key = make_num(+key);
6302 } else if (!is_identifier(key)) {
6303 key = encode_string(key);
6305 return indent(add_spaces(beautify && options.space_colon
6307 : [ key + ":", val ]));
6308 }).join("," + newline);
6309 }) + newline + indent("}");
6310 return obj_needs_parens ? "(" + out + ")" : out;
6312 "regexp": function(rx, mods) {
6313 return "/" + rx + "/" + mods;
6315 "array": function(elements) {
6316 if (elements.length == 0) return "[]";
6317 return add_spaces([ "[", add_commas(MAP(elements, function(el, i){
6318 if (!beautify && el[0] == "atom" && el[1] == "undefined") return i === elements.length - 1 ? "," : "";
6319 return parenthesize(el, "seq");
6322 "stat": function(stmt) {
6323 return make(stmt).replace(/;*\s*$/, ";");
6326 return add_commas(MAP(slice(arguments), make));
6328 "label": function(name, block) {
6329 return add_spaces([ make_name(name), ":", make(block) ]);
6331 "with": function(expr, block) {
6332 return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]);
6334 "atom": function(name) {
6335 return make_name(name);
6337 }, function(){ return make(ast) });
6339 // The squeezer replaces "block"-s that contain only a single
6340 // statement with the statement itself; technically, the AST
6341 // is correct, but this can create problems when we output an
6342 // IF having an ELSE clause where the THEN clause ends in an
6343 // IF *without* an ELSE block (then the outer ELSE would refer
6344 // to the inner IF). This function checks for this case and
6345 // adds the block brackets if needed.
6346 function make_then(th) {
6347 if (th == null) return ";";
6348 if (th[0] == "do") {
6349 // https://github.com/mishoo/UglifyJS/issues/#issue/57
6350 // IE croaks with "syntax error" on code like this:
6351 // if (foo) do ... while(cond); else ...
6352 // we need block brackets around do/while
6353 return make_block([ th ]);
6360 // no else, we must add the block
6361 return make([ "block", [ th ]]);
6364 else if (type == "while" || type == "do") b = b[2];
6365 else if (type == "for" || type == "for-in") b = b[4];
6371 function make_function(name, args, body, keyword) {
6372 var out = keyword || "function";
6374 out += " " + make_name(name);
6376 out += "(" + add_commas(MAP(args, make_name)) + ")";
6377 out = add_spaces([ out, make_block(body) ]);
6378 return needs_parens(this) ? "(" + out + ")" : out;
6381 function must_has_semicolon(node) {
6385 return empty(node[2]); // `with' or `while' with empty body?
6388 return empty(node[4]); // `for' with empty body?
6390 if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else'
6392 if (empty(node[3])) return true; // `else' present but empty
6393 return must_has_semicolon(node[3]); // dive into the `else' branch
6395 return must_has_semicolon(node[2]); // dive into the `then' branch
6399 function make_block_statements(statements, noindent) {
6400 for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
6401 var stat = statements[i];
6402 var code = make(stat);
6404 if (!beautify && i == last && !must_has_semicolon(stat)) {
6405 code = code.replace(/;+\s*$/, "");
6410 return noindent ? a : MAP(a, indent);
6413 function make_switch_block(body) {
6414 var n = body.length;
6415 if (n == 0) return "{}";
6416 return "{" + newline + MAP(body, function(branch, i){
6417 var has_body = branch[1].length > 0, code = with_indent(function(){
6418 return indent(branch[0]
6419 ? add_spaces([ "case", make(branch[0]) + ":" ])
6421 }, 0.5) + (has_body ? newline + with_indent(function(){
6422 return make_block_statements(branch[1]).join(newline);
6424 if (!beautify && has_body && i < n - 1)
6427 }).join(newline) + newline + indent("}");
6430 function make_block(statements) {
6431 if (!statements) return ";";
6432 if (statements.length == 0) return "{}";
6433 return "{" + newline + with_indent(function(){
6434 return make_block_statements(statements).join(newline);
6435 }) + newline + indent("}");
6438 function make_1vardef(def) {
6439 var name = def[0], val = def[1];
6441 name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]);
6447 function split_lines(code, max_line_length) {
6449 jsp.parse(function(){
6450 var next_token = jsp.tokenizer(code);
6453 function current_length(tok) {
6454 return tok.pos - last_split;
6456 function split_here(tok) {
6457 last_split = tok.pos;
6458 splits.push(last_split);
6461 var tok = next_token.apply(this, arguments);
6464 if (prev_token.type == "keyword") break out;
6466 if (current_length(tok) > max_line_length) {
6480 custom.context = function() {
6481 return next_token.context.apply(this, arguments);
6485 return splits.map(function(pos, i){
6486 return code.substring(pos, splits[i + 1] || code.length);
6490 /* -----[ Utilities ]----- */
6492 function repeat_string(str, i) {
6493 if (i <= 0) return "";
6494 if (i == 1) return str;
6495 var d = repeat_string(str, i >> 1);
6497 if (i & 1) d += str;
6501 function defaults(args, defs) {
6505 for (var i in defs) if (HOP(defs, i)) {
6506 ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
6511 function is_identifier(name) {
6512 return /^[a-z_$][a-z0-9_$]*$/i.test(name)
6514 && !HOP(jsp.KEYWORDS_ATOM, name)
6515 && !HOP(jsp.RESERVED_WORDS, name)
6516 && !HOP(jsp.KEYWORDS, name);
6519 function HOP(obj, prop) {
6520 return Object.prototype.hasOwnProperty.call(obj, prop);
6528 MAP = function(a, f, o) {
6529 var ret = [], top = [], i;
6531 var val = f.call(o, a[i], i);
6532 if (val instanceof AtTop) {
6534 if (val instanceof Splice) {
6535 top.push.apply(top, val.v);
6540 else if (val != skip) {
6541 if (val instanceof Splice) {
6542 ret.push.apply(ret, val.v);
6548 if (a instanceof Array) for (i = 0; i < a.length; ++i) doit();
6549 else for (i in a) if (HOP(a, i)) doit();
6550 return top.concat(ret);
6552 MAP.at_top = function(val) { return new AtTop(val) };
6553 MAP.splice = function(val) { return new Splice(val) };
6554 var skip = MAP.skip = {};
6555 function AtTop(val) { this.v = val };
6556 function Splice(val) { this.v = val };
6559 /* -----[ Exports ]----- */
6561 exports.ast_walker = ast_walker;
6562 exports.ast_mangle = ast_mangle;
6563 exports.ast_squeeze = ast_squeeze;
6564 exports.ast_lift_variables = ast_lift_variables;
6565 exports.gen_code = gen_code;
6566 exports.ast_add_scope = ast_add_scope;
6567 exports.set_logger = function(logger) { warn = logger };
6568 exports.make_string = make_string;
6569 exports.split_lines = split_lines;
6573 exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
6575 });define('uglifyjs/index', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
6577 //convienence function(src, [options]);
6578 function uglify(orig_code, options){
6579 options || (options = {});
6580 var jsp = uglify.parser;
6581 var pro = uglify.uglify;
6583 var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST
6584 ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names
6585 ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations
6586 var final_code = pro.gen_code(ast, options.gen_options); // compressed code here
6590 uglify.parser = require("./parse-js");
6591 uglify.uglify = require("./process");
6593 module.exports = uglify
6596 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
6597 * Available via the MIT or new BSD license.
6598 * see: http://github.com/jrburke/requirejs for details
6601 /*jslint plusplus: false, strict: false */
6602 /*global define: false */
6604 define('parse', ['./uglifyjs/index'], function (uglify) {
6605 var parser = uglify.parser,
6606 processor = uglify.uglify,
6607 ostring = Object.prototype.toString,
6610 if (Array.isArray) {
6611 isArray = Array.isArray;
6613 isArray = function (it) {
6614 return ostring.call(it) === "[object Array]";
6619 * Determines if the AST node is an array literal
6621 function isArrayLiteral(node) {
6622 return node[0] === 'array';
6626 * Determines if the AST node is an object literal
6628 function isObjectLiteral(node) {
6629 return node[0] === 'object';
6633 * Converts a regular JS array of strings to an AST node that
6634 * represents that array.
6635 * @param {Array} ary
6636 * @param {Node} an AST node that represents an array of strings.
6638 function toAstArray(ary) {
6645 for (i = 0; (item = ary[i]); i++) {
6656 * Validates a node as being an object literal (like for i18n bundles)
6657 * or an array literal with just string members. If an array literal,
6658 * only return array members that are full strings. So the caller of
6659 * this function should use the return value as the new value for the
6662 * This function does not need to worry about comments, they are not
6663 * present in this AST.
6665 * @param {Node} node an AST node.
6667 * @returns {Node} an AST node to use for the valid dependencies.
6668 * If null is returned, then it means the input node was not a valid
6671 function validateDeps(node) {
6672 var newDeps = ['array', []],
6679 if (isObjectLiteral(node) || node[0] === 'function') {
6683 //Dependencies can be an object literal or an array.
6684 if (!isArrayLiteral(node)) {
6688 arrayArgs = node[1];
6690 for (i = 0; i < arrayArgs.length; i++) {
6692 if (dep[0] === 'string') {
6693 newDeps[1].push(dep);
6696 return newDeps[1].length ? newDeps : null;
6700 * Gets dependencies from a node, but only if it is an array literal,
6701 * and only if the dependency is a string literal.
6703 * This function does not need to worry about comments, they are not
6704 * present in this AST.
6706 * @param {Node} node an AST node.
6708 * @returns {Array} of valid dependencies.
6709 * If null is returned, then it means the input node was not a valid
6710 * array literal, or did not have any string literals..
6712 function getValidDeps(node) {
6720 if (isObjectLiteral(node) || node[0] === 'function') {
6724 //Dependencies can be an object literal or an array.
6725 if (!isArrayLiteral(node)) {
6729 arrayArgs = node[1];
6731 for (i = 0; i < arrayArgs.length; i++) {
6733 if (dep[0] === 'string') {
6734 newDeps.push(dep[1]);
6737 return newDeps.length ? newDeps : null;
6741 * Main parse function. Returns a string of any valid require or define/require.def
6742 * calls as part of one JavaScript source string.
6743 * @param {String} moduleName the module name that represents this file.
6744 * It is used to create a default define if there is not one already for the file.
6745 * This allows properly tracing dependencies for builds. Otherwise, if
6746 * the file just has a require() call, the file dependencies will not be
6747 * properly reflected: the file will come before its dependencies.
6748 * @param {String} moduleName
6749 * @param {String} fileName
6750 * @param {String} fileContents
6751 * @param {Object} options optional options. insertNeedsDefine: true will
6752 * add calls to require.needsDefine() if appropriate.
6753 * @returns {String} JS source string or null, if no require or define/require.def
6756 function parse(moduleName, fileName, fileContents, options) {
6757 options = options || {};
6759 //Set up source input
6760 var moduleDeps = [],
6764 astRoot = parser.parse(fileContents),
6765 i, moduleCall, depString;
6767 parse.recurse(astRoot, function (callName, config, name, deps) {
6768 //If name is an array, it means it is an anonymous module,
6769 //so adjust args appropriately. An anonymous module could
6770 //have a FUNCTION as the name type, but just ignore those
6771 //since we just want to find dependencies.
6772 if (name && isArrayLiteral(name)) {
6777 if (!(deps = getValidDeps(deps))) {
6781 //Get the name as a string literal, if it is available.
6782 if (name && name[0] === 'string') {
6788 if (callName === 'define' && (!name || name === moduleName)) {
6789 needsDefine = false;
6793 //If there is no module name, the dependencies are for
6794 //this file/default module name.
6795 moduleDeps = moduleDeps.concat(deps);
6803 //If define was found, no need to dive deeper, unless
6804 //the config explicitly wants to dig deeper.
6805 return !options.findNestedDependencies;
6808 if (options.insertNeedsDefine && needsDefine) {
6809 result += 'require.needsDefine("' + moduleName + '");';
6812 if (moduleDeps.length || moduleList.length) {
6813 for (i = 0; (moduleCall = moduleList[i]); i++) {
6818 //If this is the main module for this file, combine any
6819 //"anonymous" dependencies (could come from a nested require
6820 //call) with this module.
6821 if (moduleCall.name === moduleName) {
6822 moduleCall.deps = moduleCall.deps.concat(moduleDeps);
6826 depString = moduleCall.deps.length ? '["' + moduleCall.deps.join('","') + '"]' : '[]';
6827 result += 'define("' + moduleCall.name + '",' + depString + ');';
6829 if (moduleDeps.length) {
6833 depString = moduleDeps.length ? '["' + moduleDeps.join('","') + '"]' : '[]';
6834 result += 'define("' + moduleName + '",' + depString + ');';
6838 return result ? result : null;
6841 //Add some private methods to object for use in derived objects.
6842 parse.isArray = isArray;
6843 parse.isObjectLiteral = isObjectLiteral;
6844 parse.isArrayLiteral = isArrayLiteral;
6847 * Handles parsing a file recursively for require calls.
6848 * @param {Array} parentNode the AST node to start with.
6849 * @param {Function} onMatch function to call on a parse match.
6850 * @param {Object} [options] This is normally the build config options if
6852 * @param {Function} [recurseCallback] function to call on each valid
6853 * node, defaults to parse.parseNode.
6855 parse.recurse = function (parentNode, onMatch, options, recurseCallback) {
6856 var hasHas = options && options.has,
6859 recurseCallback = recurseCallback || this.parseNode;
6861 if (isArray(parentNode)) {
6862 for (i = 0; i < parentNode.length; i++) {
6863 node = parentNode[i];
6864 if (isArray(node)) {
6865 //If has config is in play, if calls have been converted
6866 //by this point to be true/false values. So, if
6867 //options has a 'has' value, skip if branches that have
6868 //literal false values.
6870 //uglify returns if constructs in an array:
6872 //[1]: the condition, ['name', true | false] for the has replaced case.
6873 //[2]: the block to process if true
6874 //[3]: the block to process if false
6875 //For if/else if/else, the else if is in the [3],
6876 //so only ever have to deal with this structure.
6877 if (hasHas && node[0] === 'if' && node[1] && node[1][0] === 'name' &&
6878 (node[1][1] === 'true' || node[1][1] === 'false')) {
6879 if (node[1][1] === 'true') {
6880 this.recurse([node[2]], onMatch, options, recurseCallback);
6882 this.recurse([node[3]], onMatch, options, recurseCallback);
6885 if (recurseCallback(node, onMatch)) {
6886 //The onMatch indicated parsing should
6887 //stop for children of this node.
6890 this.recurse(node, onMatch, options, recurseCallback);
6898 * Determines if the file defines require().
6899 * @param {String} fileName
6900 * @param {String} fileContents
6901 * @returns {Boolean}
6903 parse.definesRequire = function (fileName, fileContents) {
6904 var astRoot = parser.parse(fileContents);
6905 return this.nodeHasRequire(astRoot);
6909 * Finds require("") calls inside a CommonJS anonymous module wrapped in a
6910 * define(function(require, exports, module){}) wrapper. These dependencies
6911 * will be added to a modified define() call that lists the dependencies
6912 * on the outside of the function.
6913 * @param {String} fileName
6914 * @param {String} fileContents
6915 * @returns {Array} an array of module names that are dependencies. Always
6916 * returns an array, but could be of length zero.
6918 parse.getAnonDeps = function (fileName, fileContents) {
6919 var astRoot = parser.parse(fileContents),
6920 defFunc = this.findAnonDefineFactory(astRoot);
6922 return parse.getAnonDepsFromNode(defFunc);
6926 * Finds require("") calls inside a CommonJS anonymous module wrapped
6927 * in a define function, given an AST node for the definition function.
6928 * @param {Node} node the AST node for the definition function.
6929 * @returns {Array} and array of dependency names. Can be of zero length.
6931 parse.getAnonDepsFromNode = function (node) {
6936 this.findRequireDepNames(node, deps);
6938 //If no deps, still add the standard CommonJS require, exports, module,
6939 //in that order, to the deps, but only if specified as function args.
6940 //In particular, if exports is used, it is favored over the return
6941 //value of the function, so only add it if asked.
6942 funcArgLength = node[2] && node[2].length;
6943 if (funcArgLength) {
6944 deps = (funcArgLength > 1 ? ["require", "exports", "module"] :
6945 ["require"]).concat(deps);
6952 * Finds the function in define(function (require, exports, module){});
6953 * @param {Array} node
6954 * @returns {Boolean}
6956 parse.findAnonDefineFactory = function (node) {
6957 var callback, i, n, call, args;
6959 if (isArray(node)) {
6960 if (node[0] === 'call') {
6963 if ((call[0] === 'name' && call[1] === 'define') ||
6964 (call[0] === 'dot' && call[1][1] === 'require' && call[2] === 'def')) {
6966 //There should only be one argument and it should be a function,
6967 //or a named module with function as second arg
6968 if (args.length === 1 && args[0][0] === 'function') {
6970 } else if (args.length === 2 && args[0][0] === 'string' &&
6971 args[1][0] === 'function') {
6978 for (i = 0; i < node.length; i++) {
6980 if ((callback = this.findAnonDefineFactory(n))) {
6990 * Finds any config that is passed to requirejs.
6991 * @param {String} fileName
6992 * @param {String} fileContents
6994 * @returns {Object} a config object. Will be null if no config.
6995 * Can throw an error if the config in the file cannot be evaluated in
6996 * a build context to valid JavaScript.
6998 parse.findConfig = function (fileName, fileContents) {
6999 /*jslint evil: true */
7000 //This is a litle bit inefficient, it ends up with two uglifyjs parser
7001 //calls. Can revisit later, but trying to build out larger functional
7003 var foundConfig = null,
7004 astRoot = parser.parse(fileContents);
7006 parse.recurse(astRoot, function (configNode) {
7009 if (!foundConfig && configNode) {
7010 jsConfig = parse.nodeToString(configNode);
7011 foundConfig = eval('(' + jsConfig + ')');
7015 }, null, parse.parseConfigNode);
7021 * Finds all dependencies specified in dependency arrays and inside
7022 * simplified commonjs wrappers.
7023 * @param {String} fileName
7024 * @param {String} fileContents
7026 * @returns {Array} an array of dependency strings. The dependencies
7027 * have not been normalized, they may be relative IDs.
7029 parse.findDependencies = function (fileName, fileContents, options) {
7030 //This is a litle bit inefficient, it ends up with two uglifyjs parser
7031 //calls. Can revisit later, but trying to build out larger functional
7033 var dependencies = [],
7034 astRoot = parser.parse(fileContents);
7036 parse.recurse(astRoot, function (callName, config, name, deps) {
7037 //Normalize the input args.
7038 if (name && isArrayLiteral(name)) {
7043 if ((deps = getValidDeps(deps))) {
7044 dependencies = dependencies.concat(deps);
7048 return dependencies;
7052 * Finds only CJS dependencies, ones that are the form require('stringLiteral')
7054 parse.findCjsDependencies = function (fileName, fileContents, options) {
7055 //This is a litle bit inefficient, it ends up with two uglifyjs parser
7056 //calls. Can revisit later, but trying to build out larger functional
7058 var dependencies = [],
7059 astRoot = parser.parse(fileContents);
7061 parse.recurse(astRoot, function (dep) {
7062 dependencies.push(dep);
7063 }, options, function (node, onMatch) {
7067 if (!isArray(node)) {
7071 if (node[0] === 'call') {
7076 //A require('') use.
7077 if (call[0] === 'name' && call[1] === 'require' &&
7078 args[0][0] === 'string') {
7079 return onMatch(args[0][1]);
7088 return dependencies;
7092 * Determines if define(), require({}|[]) or requirejs was called in the
7093 * file. Also finds out if define() is declared and if define.amd is called.
7095 parse.usesAmdOrRequireJs = function (fileName, fileContents, options) {
7096 var astRoot = parser.parse(fileContents),
7099 parse.recurse(astRoot, function (prop) {
7104 }, options, parse.findAmdOrRequireJsNode);
7110 * Determines if require(''), exports.x =, module.exports =,
7111 * __dirname, __filename are used. So, not strictly traditional CommonJS,
7112 * also checks for Node variants.
7114 parse.usesCommonJs = function (fileName, fileContents, options) {
7116 assignsExports = false,
7117 astRoot = parser.parse(fileContents);
7119 parse.recurse(astRoot, function (prop) {
7120 if (prop === 'varExports') {
7121 assignsExports = true;
7122 } else if (prop !== 'exports' || !assignsExports) {
7128 }, options, function (node, onMatch) {
7132 if (!isArray(node)) {
7136 if (node[0] === 'name' && (node[1] === '__dirname' || node[1] === '__filename')) {
7137 return onMatch(node[1].substring(2));
7138 } else if (node[0] === 'var' && node[1] && node[1][0] && node[1][0][0] === 'exports') {
7139 //Hmm, a variable assignment for exports, so does not use cjs exports.
7140 return onMatch('varExports');
7141 } else if (node[0] === 'assign' && node[2] && node[2][0] === 'dot') {
7145 //An exports or module.exports assignment.
7146 if (args[0] === 'name' && args[1] === 'module' &&
7147 node[2][2] === 'exports') {
7148 return onMatch('moduleExports');
7149 } else if (args[0] === 'name' && args[1] === 'exports') {
7150 return onMatch('exports');
7153 } else if (node[0] === 'call') {
7158 //A require('') use.
7159 if (call[0] === 'name' && call[1] === 'require' &&
7160 args[0][0] === 'string') {
7161 return onMatch('require');
7174 parse.findRequireDepNames = function (node, deps) {
7175 var moduleName, i, n, call, args;
7177 if (isArray(node)) {
7178 if (node[0] === 'call') {
7182 if (call && call[0] === 'name' && call[1] === 'require') {
7183 moduleName = args[0];
7184 if (moduleName[0] === 'string') {
7185 deps.push(moduleName[1]);
7193 for (i = 0; i < node.length; i++) {
7195 this.findRequireDepNames(n, deps);
7201 * Determines if a given node contains a require() definition.
7202 * @param {Array} node
7203 * @returns {Boolean}
7205 parse.nodeHasRequire = function (node) {
7206 if (this.isDefineNode(node)) {
7210 if (isArray(node)) {
7211 for (var i = 0, n; i < node.length; i++) {
7213 if (this.nodeHasRequire(n)) {
7223 * Is the given node the actual definition of define(). Actually uses
7224 * the definition of define.amd to find require.
7225 * @param {Array} node
7226 * @returns {Boolean}
7228 parse.isDefineNode = function (node) {
7229 //Actually look for the define.amd = assignment, since
7230 //that is more indicative of RequireJS vs a plain require definition.
7236 if (node[0] === 'assign' && node[1] === true) {
7238 if (assign[0] === 'dot' && assign[1][0] === 'name' &&
7239 assign[1][1] === 'define' && assign[2] === 'amd') {
7247 * Determines if a specific node is a valid require or define/require.def call.
7248 * @param {Array} node
7249 * @param {Function} onMatch a function to call when a match is found.
7250 * It is passed the match name, and the config, name, deps possible args.
7251 * The config, name and deps args are not normalized.
7253 * @returns {String} a JS source string with the valid require/define call.
7256 parse.parseNode = function (node, onMatch) {
7257 var call, name, config, deps, args, cjsDeps;
7259 if (!isArray(node)) {
7263 if (node[0] === 'call') {
7268 if (call[0] === 'name' &&
7269 (call[1] === 'require' || call[1] === 'requirejs')) {
7271 //It is a plain require() call.
7274 if (isArrayLiteral(config)) {
7279 if (!(deps = validateDeps(deps))) {
7283 return onMatch("require", null, null, deps);
7285 } else if (call[0] === 'name' && call[1] === 'define') {
7290 //Only allow define calls that match what is expected
7292 //* first arg should be string, array, function or object
7293 //* second arg optional, or array, function or object.
7294 //This helps weed out calls to a non-AMD define, but it is
7295 //not completely robust. Someone could create a define
7296 //function that still matches this shape, but this is the
7297 //best that is possible, and at least allows UglifyJS,
7298 //which does create its own internal define in one file,
7300 if (((name[0] === 'string' || isArrayLiteral(name) ||
7301 name[0] === 'function' || isObjectLiteral(name))) &&
7302 (!deps || isArrayLiteral(deps) ||
7303 deps[0] === 'function' || isObjectLiteral(deps) ||
7304 // allow define(['dep'], factory) pattern
7305 (isArrayLiteral(name) && deps[0] === 'name' && args.length === 2))) {
7307 //If first arg is a function, could be a commonjs wrapper,
7308 //look inside for commonjs dependencies.
7309 //Also, if deps is a function look for commonjs deps.
7310 if (name && name[0] === 'function') {
7311 cjsDeps = parse.getAnonDepsFromNode(name);
7312 if (cjsDeps.length) {
7313 name = toAstArray(cjsDeps);
7315 } else if (deps && deps[0] === 'function') {
7316 cjsDeps = parse.getAnonDepsFromNode(deps);
7317 if (cjsDeps.length) {
7318 deps = toAstArray(cjsDeps);
7322 return onMatch("define", null, name, deps);
7332 * Looks for define(), require({} || []), requirejs({} || []) calls.
7334 parse.findAmdOrRequireJsNode = function (node, onMatch) {
7335 var call, args, configNode, type;
7337 if (!isArray(node)) {
7341 if (node[0] === 'defun' && node[1] === 'define') {
7342 type = 'declaresDefine';
7343 } else if (node[0] === 'assign' && node[2] && node[2][2] === 'amd' &&
7344 node[2][1] && node[2][1][0] === 'name' &&
7345 node[2][1][1] === 'define') {
7347 } else if (node[0] === 'call') {
7352 if ((call[0] === 'dot' &&
7353 (call[1] && call[1][0] === 'name' &&
7354 (call[1][1] === 'require' || call[1][1] === 'requirejs')) &&
7355 call[2] === 'config')) {
7356 //A require.config() or requirejs.config() call.
7357 type = call[1][1] + 'Config';
7358 } else if (call[0] === 'name' &&
7359 (call[1] === 'require' || call[1] === 'requirejs')) {
7360 //A require() or requirejs() config call.
7361 //Only want ones that start with an object or an array.
7362 configNode = args[0];
7363 if (configNode[0] === 'object' || configNode[0] === 'array') {
7366 } else if (call[0] === 'name' && call[1] === 'define') {
7374 return onMatch(type);
7381 * Determines if a specific node is a valid require/requirejs config
7382 * call. That includes calls to require/requirejs.config().
7383 * @param {Array} node
7384 * @param {Function} onMatch a function to call when a match is found.
7385 * It is passed the match name, and the config, name, deps possible args.
7386 * The config, name and deps args are not normalized.
7388 * @returns {String} a JS source string with the valid require/define call.
7391 parse.parseConfigNode = function (node, onMatch) {
7392 var call, configNode, args;
7394 if (!isArray(node)) {
7398 if (node[0] === 'call') {
7403 //A require.config() or requirejs.config() call.
7404 if ((call[0] === 'dot' &&
7405 (call[1] && call[1][0] === 'name' &&
7406 (call[1][1] === 'require' || call[1][1] === 'requirejs')) &&
7407 call[2] === 'config') ||
7408 //A require() or requirejs() config call.
7410 (call[0] === 'name' &&
7411 (call[1] === 'require' || call[1] === 'requirejs'))
7413 //It is a plain require() call.
7414 configNode = args[0];
7416 if (configNode[0] !== 'object') {
7420 return onMatch(configNode);
7430 * Converts an AST node into a JS source string. Does not maintain formatting
7431 * or even comments from original source, just returns valid JS source.
7432 * @param {Array} node
7433 * @returns {String} a JS source string.
7435 parse.nodeToString = function (node) {
7436 return processor.gen_code(node, true);
7442 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
7443 * Available via the MIT or new BSD license.
7444 * see: http://github.com/jrburke/requirejs for details
7447 /*jslint regexp: false, strict: false, plusplus: false */
7448 /*global define: false */
7450 define('pragma', ['parse', 'logger'], function (parse, logger) {
7454 function create(obj, mixin) {
7455 Temp.prototype = obj;
7456 var temp = new Temp(), prop;
7458 //Avoid any extra memory hanging around
7459 Temp.prototype = null;
7462 for (prop in mixin) {
7463 if (mixin.hasOwnProperty(prop) && !(prop in temp)) {
7464 temp[prop] = mixin[prop];
7469 return temp; // Object
7473 conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/,
7474 useStrictRegExp: /['"]use strict['"];/g,
7475 hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
7476 nsRegExp: /(^|[^\.])(requirejs|require|define)\s*\(/,
7477 nsWrapRegExp: /\/\*requirejs namespace: true \*\//,
7478 apiDefRegExp: /var requirejs, require, define;/,
7479 defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g,
7480 defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g,
7481 defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
7482 defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/,
7483 amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*'function'\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g,
7485 removeStrict: function (contents, config) {
7486 return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, '');
7489 namespace: function (fileContents, ns, onLifecycleName) {
7491 //Namespace require/define calls
7492 fileContents = fileContents.replace(pragma.nsRegExp, '$1' + ns + '.$2(');
7494 //Namespace define ternary use:
7495 fileContents = fileContents.replace(pragma.defineTernaryRegExp,
7496 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd ? " + ns + ".define");
7498 //Namespace define jquery use:
7499 fileContents = fileContents.replace(pragma.defineJQueryRegExp,
7500 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd && " + ns + ".define.amd.jQuery");
7502 //Namespace has.js define use:
7503 fileContents = fileContents.replace(pragma.defineHasRegExp,
7504 "typeof " + ns + ".define === 'function' && typeof " + ns + ".define.amd === 'object' && " + ns + ".define.amd");
7506 //Namespace define checks.
7507 //Do this one last, since it is a subset of the more specific
7509 fileContents = fileContents.replace(pragma.defineCheckRegExp,
7510 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd");
7512 //Check for require.js with the require/define definitions
7513 if (pragma.apiDefRegExp.test(fileContents) &&
7514 fileContents.indexOf("if (typeof " + ns + " === 'undefined')") === -1) {
7515 //Wrap the file contents in a typeof check, and a function
7516 //to contain the API globals.
7517 fileContents = "var " + ns + ";(function () { if (typeof " +
7518 ns + " === 'undefined') {\n" +
7522 ns + ".requirejs = requirejs;" +
7523 ns + ".require = require;" +
7524 ns + ".define = define;\n" +
7528 //Finally, if the file wants a special wrapper because it ties
7529 //in to the requirejs internals in a way that would not fit
7530 //the above matches, do that. Look for /*requirejs namespace: true*/
7531 if (pragma.nsWrapRegExp.test(fileContents)) {
7532 //Remove the pragma.
7533 fileContents = fileContents.replace(pragma.nsWrapRegExp, '');
7535 //Alter the contents.
7536 fileContents = '(function () {\n' +
7537 'var require = ' + ns + '.require,' +
7538 'requirejs = ' + ns + '.requirejs,' +
7539 'define = ' + ns + '.define;\n' +
7545 return fileContents;
7549 * processes the fileContents for some //>> conditional statements
7551 process: function (fileName, fileContents, config, onLifecycleName, pluginCollector) {
7552 /*jslint evil: true */
7553 var foundIndex = -1, startIndex = 0, lineEndIndex, conditionLine,
7554 matches, type, marker, condition, isTrue, endRegExp, endMatches,
7555 endMarkerIndex, shouldInclude, startLength, lifecycleHas, deps,
7557 lifecyclePragmas, pragmas = config.pragmas, hasConfig = config.has,
7558 //Legacy arg defined to help in dojo conversion script. Remove later
7559 //when dojo no longer needs conversion:
7562 //Mix in a specific lifecycle scoped object, to allow targeting
7563 //some pragmas/has tests to only when files are saved, or at different
7564 //lifecycle events. Do not bother with kwArgs in this section, since
7565 //the old dojo kwArgs were for all points in the build lifecycle.
7566 if (onLifecycleName) {
7567 lifecyclePragmas = config['pragmas' + onLifecycleName];
7568 lifecycleHas = config['has' + onLifecycleName];
7570 if (lifecyclePragmas) {
7571 pragmas = create(pragmas || {}, lifecyclePragmas);
7575 hasConfig = create(hasConfig || {}, lifecycleHas);
7579 //Replace has references if desired
7581 fileContents = fileContents.replace(pragma.hasRegExp, function (match, test) {
7582 if (test in hasConfig) {
7583 return !!hasConfig[test];
7589 if (!config.skipPragmas) {
7591 while ((foundIndex = fileContents.indexOf("//>>", startIndex)) !== -1) {
7592 //Found a conditional. Get the conditional line.
7593 lineEndIndex = fileContents.indexOf("\n", foundIndex);
7594 if (lineEndIndex === -1) {
7595 lineEndIndex = fileContents.length - 1;
7598 //Increment startIndex past the line so the next conditional search can be done.
7599 startIndex = lineEndIndex + 1;
7601 //Break apart the conditional.
7602 conditionLine = fileContents.substring(foundIndex, lineEndIndex + 1);
7603 matches = conditionLine.match(pragma.conditionalRegExp);
7606 marker = matches[2];
7607 condition = matches[3];
7609 //See if the condition is true.
7611 isTrue = !!eval("(" + condition + ")");
7613 throw "Error in file: " +
7615 ". Conditional comment: " +
7617 " failed with this error: " + e;
7620 //Find the endpoint marker.
7621 endRegExp = new RegExp('\\/\\/\\>\\>\\s*' + type + 'End\\(\\s*[\'"]' + marker + '[\'"]\\s*\\)', "g");
7622 endMatches = endRegExp.exec(fileContents.substring(startIndex, fileContents.length));
7624 endMarkerIndex = startIndex + endRegExp.lastIndex - endMatches[0].length;
7626 //Find the next line return based on the match position.
7627 lineEndIndex = fileContents.indexOf("\n", endMarkerIndex);
7628 if (lineEndIndex === -1) {
7629 lineEndIndex = fileContents.length - 1;
7632 //Should we include the segment?
7633 shouldInclude = ((type === "exclude" && !isTrue) || (type === "include" && isTrue));
7635 //Remove the conditional comments, and optionally remove the content inside
7636 //the conditional comments.
7637 startLength = startIndex - foundIndex;
7638 fileContents = fileContents.substring(0, foundIndex) +
7639 (shouldInclude ? fileContents.substring(startIndex, endMarkerIndex) : "") +
7640 fileContents.substring(lineEndIndex + 1, fileContents.length);
7642 //Move startIndex to foundIndex, since that is the new position in the file
7643 //where we need to look for more conditionals in the next while loop pass.
7644 startIndex = foundIndex;
7646 throw "Error in file: " +
7648 ". Cannot find end marker for conditional comment: " +
7656 //If need to find all plugin resources to optimize, do that now,
7657 //before namespacing, since the namespacing will change the API
7659 //If there is a plugin collector, scan the file for plugin resources.
7660 if (config.optimizeAllPluginResources && pluginCollector) {
7662 deps = parse.findDependencies(fileName, fileContents);
7664 for (i = 0; (dep = deps[i]); i++) {
7665 if (dep.indexOf('!') !== -1) {
7666 (pluginCollector[moduleName] ||
7667 (pluginCollector[moduleName] = [])).push(dep);
7672 logger.error('Parse error looking for plugin resources in ' +
7673 fileName + ', skipping.');
7677 //Strip amdefine use for node-shared modules.
7678 fileContents = fileContents.replace(pragma.amdefineRegExp, '');
7681 if (onLifecycleName === 'OnSave' && config.namespace) {
7682 fileContents = pragma.namespace(fileContents, config.namespace, onLifecycleName);
7686 return pragma.removeStrict(fileContents, config);
7692 if(env === 'node') {
7694 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
7695 * Available via the MIT or new BSD license.
7696 * see: http://github.com/jrburke/requirejs for details
7699 /*jslint strict: false */
7700 /*global define: false */
7702 define('node/optimize', {});
7706 if(env === 'rhino') {
7708 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
7709 * Available via the MIT or new BSD license.
7710 * see: http://github.com/jrburke/requirejs for details
7713 /*jslint strict: false, plusplus: false */
7714 /*global define: false, java: false, Packages: false */
7716 define('rhino/optimize', ['logger'], function (logger) {
7718 //Add .reduce to Rhino so UglifyJS can run in Rhino,
7719 //inspired by https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
7720 //but rewritten for brevity, and to be good enough for use by UglifyJS.
7721 if (!Array.prototype.reduce) {
7722 Array.prototype.reduce = function (fn /*, initialValue */) {
7724 length = this.length,
7727 if (arguments.length >= 2) {
7728 accumulator = arguments[1];
7732 accumulator = this[i++];
7739 for (; i < length; i++) {
7741 accumulator = fn.call(undefined, accumulator, this[i], i, this);
7749 var JSSourceFilefromCode, optimize;
7751 //Bind to Closure compiler, but if it is not available, do not sweat it.
7753 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.JSSourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]);
7756 //Helper for closure compiler, because of weird Java-JavaScript interactions.
7757 function closurefromCode(filename, content) {
7758 return JSSourceFilefromCode.invoke(null, [filename, content]);
7762 closure: function (fileName, fileContents, keepLines, config) {
7763 config = config || {};
7764 var jscomp = Packages.com.google.javascript.jscomp,
7765 flags = Packages.com.google.common.flags,
7767 externSourceFile = closurefromCode("fakeextern.js", " "),
7768 //Set up source input
7769 jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
7770 options, option, FLAG_compilation_level, compiler,
7771 Compiler = Packages.com.google.javascript.jscomp.Compiler,
7774 logger.trace("Minifying file: " + fileName);
7777 options = new jscomp.CompilerOptions();
7778 for (option in config.CompilerOptions) {
7779 // options are false by default and jslint wanted an if statement in this for loop
7780 if (config.CompilerOptions[option]) {
7781 options[option] = config.CompilerOptions[option];
7785 options.prettyPrint = keepLines || options.prettyPrint;
7787 FLAG_compilation_level = jscomp.CompilationLevel[config.CompilationLevel || 'SIMPLE_OPTIMIZATIONS'];
7788 FLAG_compilation_level.setOptionsForCompilationLevel(options);
7790 //Trigger the compiler
7791 Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']);
7792 compiler = new Compiler();
7794 result = compiler.compile(externSourceFile, jsSourceFile, options);
7795 if (!result.success) {
7796 logger.error('Cannot closure compile file: ' + fileName + '. Skipping it.');
7798 fileContents = compiler.toSource();
7801 return fileContents;
7809 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
7810 * Available via the MIT or new BSD license.
7811 * see: http://github.com/jrburke/requirejs for details
7814 /*jslint plusplus: false, nomen: false, regexp: false */
7815 /*global define: false */
7817 define('optimize', [ 'lang', 'logger', 'env!env/optimize', 'env!env/file', 'parse',
7818 'pragma', 'uglifyjs/index'],
7819 function (lang, logger, envOptimize, file, parse,
7823 cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/g,
7824 cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g;
7827 * If an URL from a CSS url value contains start/end quotes, remove them.
7828 * This is not done in the regexp, since my regexp fu is not that strong,
7829 * and the CSS spec allows for ' and " in the URL if they are backslash escaped.
7830 * @param {String} url
7832 function cleanCssUrlQuotes(url) {
7833 //Make sure we are not ending in whitespace.
7834 //Not very confident of the css regexps above that there will not be ending
7836 url = url.replace(/\s+$/, "");
7838 if (url.charAt(0) === "'" || url.charAt(0) === "\"") {
7839 url = url.substring(1, url.length - 1);
7846 * Inlines nested stylesheets that have @import calls in them.
7847 * @param {String} fileName the file name
7848 * @param {String} fileContents the file contents
7849 * @param {String} cssImportIgnore comma delimited string of files to ignore
7850 * @param {Object} included an object used to track the files already imported
7852 function flattenCss(fileName, fileContents, cssImportIgnore, included) {
7853 //Find the last slash in the name.
7854 fileName = fileName.replace(lang.backSlashRegExp, "/");
7855 var endIndex = fileName.lastIndexOf("/"),
7856 //Make a file path based on the last slash.
7857 //If no slash, so must be just a file name. Use empty string then.
7858 filePath = (endIndex !== -1) ? fileName.substring(0, endIndex + 1) : "",
7859 //store a list of merged files
7862 //Make sure we have a delimited ignore list to make matching faster
7863 if (cssImportIgnore && cssImportIgnore.charAt(cssImportIgnore.length - 1) !== ",") {
7864 cssImportIgnore += ",";
7867 fileContents = fileContents.replace(cssImportRegExp, function (fullMatch, urlStart, importFileName, urlEnd, mediaTypes) {
7868 //Only process media type "all" or empty media type rules.
7869 if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) {
7873 importFileName = cleanCssUrlQuotes(importFileName);
7875 //Ignore the file import if it is part of an ignore list.
7876 if (cssImportIgnore && cssImportIgnore.indexOf(importFileName + ",") !== -1) {
7880 //Make sure we have a unix path for the rest of the operation.
7881 importFileName = importFileName.replace(lang.backSlashRegExp, "/");
7884 //if a relative path, then tack on the filePath.
7885 //If it is not a relative path, then the readFile below will fail,
7886 //and we will just skip that import.
7887 var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName,
7888 importContents = file.readFile(fullImportFileName), i,
7889 importEndIndex, importPath, fixedUrlMatch, colonIndex, parts, flat;
7891 //Skip the file if it has already been included.
7892 if (included[fullImportFileName]) {
7895 included[fullImportFileName] = true;
7897 //Make sure to flatten any nested imports.
7898 flat = flattenCss(fullImportFileName, importContents, cssImportIgnore, included);
7899 importContents = flat.fileContents;
7901 if (flat.importList.length) {
7902 importList.push.apply(importList, flat.importList);
7905 //Make the full import path
7906 importEndIndex = importFileName.lastIndexOf("/");
7908 //Make a file path based on the last slash.
7909 //If no slash, so must be just a file name. Use empty string then.
7910 importPath = (importEndIndex !== -1) ? importFileName.substring(0, importEndIndex + 1) : "";
7912 //fix url() on relative import (#5)
7913 importPath = importPath.replace(/^\.\//, '');
7915 //Modify URL paths to match the path represented by this file.
7916 importContents = importContents.replace(cssUrlRegExp, function (fullMatch, urlMatch) {
7917 fixedUrlMatch = cleanCssUrlQuotes(urlMatch);
7918 fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/");
7920 //Only do the work for relative URLs. Skip things that start with / or have
7922 colonIndex = fixedUrlMatch.indexOf(":");
7923 if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) {
7924 //It is a relative URL, tack on the path prefix
7925 urlMatch = importPath + fixedUrlMatch;
7927 logger.trace(importFileName + "\n URL not a relative URL, skipping: " + urlMatch);
7931 parts = urlMatch.split("/");
7932 for (i = parts.length - 1; i > 0; i--) {
7933 if (parts[i] === ".") {
7935 } else if (parts[i] === "..") {
7936 if (i !== 0 && parts[i - 1] !== "..") {
7937 parts.splice(i - 1, 2);
7943 return "url(" + parts.join("/") + ")";
7946 importList.push(fullImportFileName);
7947 return importContents;
7949 logger.warn(fileName + "\n Cannot inline css import, skipping: " + importFileName);
7955 importList : importList,
7956 fileContents : fileContents
7961 licenseCommentRegExp: /\/\*[\s\S]*?\*\//g,
7964 * Optimizes a file that contains JavaScript content. Optionally collects
7965 * plugin resources mentioned in a file, and then passes the content
7966 * through an minifier if one is specified via config.optimize.
7968 * @param {String} fileName the name of the file to optimize
7969 * @param {String} outFileName the name of the file to use for the
7970 * saved optimized content.
7971 * @param {Object} config the build config object.
7972 * @param {String} [moduleName] the module name to use for the file.
7973 * Used for plugin resource collection.
7974 * @param {Array} [pluginCollector] storage for any plugin resources
7977 jsFile: function (fileName, outFileName, config, moduleName, pluginCollector) {
7978 var parts = (config.optimize + "").split('.'),
7979 optimizerName = parts[0],
7980 keepLines = parts[1] === 'keepLines',
7983 fileContents = file.readFile(fileName);
7985 fileContents = optimize.js(fileName, fileContents, optimizerName,
7986 keepLines, config, pluginCollector);
7988 file.saveUtf8File(outFileName, fileContents);
7992 * Optimizes a file that contains JavaScript content. Optionally collects
7993 * plugin resources mentioned in a file, and then passes the content
7994 * through an minifier if one is specified via config.optimize.
7996 * @param {String} fileName the name of the file that matches the
7998 * @param {String} fileContents the string of JS to optimize.
7999 * @param {String} [optimizerName] optional name of the optimizer to
8000 * use. 'uglify' is default.
8001 * @param {Boolean} [keepLines] whether to keep line returns in the optimization.
8002 * @param {Object} [config] the build config object.
8003 * @param {Array} [pluginCollector] storage for any plugin resources
8006 js: function (fileName, fileContents, optimizerName, keepLines, config, pluginCollector) {
8007 var licenseContents = '',
8008 optFunc, match, comment;
8010 config = config || {};
8012 //Apply pragmas/namespace renaming
8013 fileContents = pragma.process(fileName, fileContents, config, 'OnSave', pluginCollector);
8015 //Optimize the JS files if asked.
8016 if (optimizerName && optimizerName !== 'none') {
8017 optFunc = envOptimize[optimizerName] || optimize.optimizers[optimizerName];
8019 throw new Error('optimizer with name of "' +
8021 '" not found for this environment');
8024 if (config.preserveLicenseComments) {
8025 //Pull out any license comments for prepending after optimization.
8026 optimize.licenseCommentRegExp.lastIndex = 0;
8027 while ((match = optimize.licenseCommentRegExp.exec(fileContents))) {
8029 //Only keep the comments if they are license comments.
8030 if (comment.indexOf('@license') !== -1 ||
8031 comment.indexOf('/*!') === 0) {
8032 licenseContents += comment + '\n';
8037 fileContents = licenseContents + optFunc(fileName, fileContents, keepLines,
8038 config[optimizerName]);
8041 return fileContents;
8045 * Optimizes one CSS file, inlining @import calls, stripping comments, and
8046 * optionally removes line returns.
8047 * @param {String} fileName the path to the CSS file to optimize
8048 * @param {String} outFileName the path to save the optimized file.
8049 * @param {Object} config the config object with the optimizeCss and
8050 * cssImportIgnore options.
8052 cssFile: function (fileName, outFileName, config) {
8054 //Read in the file. Make sure we have a JS string.
8055 var originalFileContents = file.readFile(fileName),
8056 flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, {}),
8057 fileContents = flat.fileContents,
8058 startIndex, endIndex, buildText;
8060 //Do comment removal.
8062 if (config.optimizeCss.indexOf(".keepComments") === -1) {
8064 //Get rid of comments.
8065 while ((startIndex = fileContents.indexOf("/*")) !== -1) {
8066 endIndex = fileContents.indexOf("*/", startIndex + 2);
8067 if (endIndex === -1) {
8068 throw "Improper comment in CSS file: " + fileName;
8070 fileContents = fileContents.substring(0, startIndex) + fileContents.substring(endIndex + 2, fileContents.length);
8073 //Get rid of newlines.
8074 if (config.optimizeCss.indexOf(".keepLines") === -1) {
8075 fileContents = fileContents.replace(/[\r\n]/g, "");
8076 fileContents = fileContents.replace(/\s+/g, " ");
8077 fileContents = fileContents.replace(/\{\s/g, "{");
8078 fileContents = fileContents.replace(/\s\}/g, "}");
8080 //Remove multiple empty lines.
8081 fileContents = fileContents.replace(/(\r\n)+/g, "\r\n");
8082 fileContents = fileContents.replace(/(\n)+/g, "\n");
8085 fileContents = originalFileContents;
8086 logger.error("Could not optimized CSS file: " + fileName + ", error: " + e);
8089 file.saveUtf8File(outFileName, fileContents);
8091 //text output to stdout and/or written to build.txt file
8092 buildText = "\n"+ outFileName.replace(config.dir, "") +"\n----------------\n";
8093 flat.importList.push(fileName);
8094 buildText += flat.importList.map(function(path){
8095 return path.replace(config.dir, "");
8097 return buildText +"\n";
8101 * Optimizes CSS files, inlining @import calls, stripping comments, and
8102 * optionally removes line returns.
8103 * @param {String} startDir the path to the top level directory
8104 * @param {Object} config the config object with the optimizeCss and
8105 * cssImportIgnore options.
8107 css: function (startDir, config) {
8109 i, fileName, fileList;
8110 if (config.optimizeCss.indexOf("standard") !== -1) {
8111 fileList = file.getFilteredFileList(startDir, /\.css$/, true);
8113 for (i = 0; i < fileList.length; i++) {
8114 fileName = fileList[i];
8115 logger.trace("Optimizing (" + config.optimizeCss + ") CSS file: " + fileName);
8116 buildText += optimize.cssFile(fileName, fileName, config);
8124 uglify: function (fileName, fileContents, keepLines, config) {
8125 var parser = uglify.parser,
8126 processor = uglify.uglify,
8129 config = config || {};
8131 logger.trace("Uglifying file: " + fileName);
8134 ast = parser.parse(fileContents, config.strict_semicolons);
8135 ast = processor.ast_mangle(ast, config);
8136 ast = processor.ast_squeeze(ast, config);
8138 fileContents = processor.gen_code(ast, config);
8140 logger.error('Cannot uglify file: ' + fileName + '. Skipping it. Error is:\n' + e.toString());
8142 return fileContents;
8150 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
8151 * Available via the MIT or new BSD license.
8152 * see: http://github.com/jrburke/requirejs for details
8155 * This file patches require.js to communicate with the build system.
8158 /*jslint nomen: false, plusplus: false, regexp: false, strict: false */
8159 /*global require: false, define: true */
8161 //NOT asking for require as a dependency since the goal is to modify the
8162 //global require below
8163 define('requirePatch', [ 'env!env/file', 'pragma', 'parse'],
8164 function (file, pragma, parse) {
8166 var allowRun = true;
8168 //This method should be called when the patches to require should take hold.
8169 return function () {
8176 pluginBuilderRegExp = /(["']?)pluginBuilder(["']?)\s*[=\:]\s*["']([^'"\s]+)["']/,
8180 /** Print out some extrs info about the module tree that caused the error. **/
8181 require.onError = function (err) {
8183 var msg = '\nIn module tree:\n',
8184 standardIndent = ' ',
8185 tree = err.moduleTree,
8188 if (tree && tree.length > 0) {
8189 for (i = tree.length - 1; i > -1 && (mod = tree[i]); i--) {
8190 for (j = tree.length - i; j > -1; j--) {
8191 msg += standardIndent;
8196 err = new Error(err.toString() + msg);
8202 //Stored cached file contents for reuse in other layers.
8203 require._cachedFileContents = {};
8205 /** Reset state for each build layer pass. */
8206 require._buildReset = function () {
8207 var oldContext = require.s.contexts._;
8209 //Clear up the existing context.
8210 delete require.s.contexts._;
8212 //Set up new context, so the layer object can hold onto it.
8215 layer = require._layer = {
8217 buildFileToModule: {},
8220 modulesWithNames: {},
8222 existingRequireUrl: "",
8223 context: require.s.contexts._
8226 //Return the previous context in case it is needed, like for
8227 //the basic config object.
8231 require._buildReset();
8234 * Makes sure the URL is something that can be supported by the
8235 * optimization tool.
8236 * @param {String} url
8237 * @returns {Boolean}
8239 require._isSupportedBuildUrl = function (url) {
8240 //Ignore URLs with protocols, hosts or question marks, means either network
8241 //access is needed to fetch it or it is too dynamic. Note that
8242 //on Windows, full paths are used for some urls, which include
8243 //the drive, like c:/something, so need to test for something other
8244 //than just a colon.
8245 return url.indexOf("://") === -1 && url.indexOf("?") === -1 &&
8246 url.indexOf('empty:') !== 0 && url.indexOf('//') !== 0;
8249 //Override define() to catch modules that just define an object, so that
8250 //a dummy define call is not put in the build file for them. They do
8251 //not end up getting defined via require.execCb, so we need to catch them
8252 //at the define call.
8255 //This function signature does not have to be exact, just match what we
8257 define = function (name, obj) {
8258 if (typeof name === "string" && !layer.needsDefine[name]) {
8259 layer.modulesWithNames[name] = true;
8261 return oldDef.apply(require, arguments);
8264 define.amd = oldDef.amd;
8266 //Add some utilities for plugins
8267 require._readFile = file.readFile;
8268 require._fileExists = function (path) {
8269 return file.exists(path);
8272 function normalizeUrlWithBase(context, moduleName, url) {
8273 //Adjust the URL if it was not transformed to use baseUrl.
8274 if (require.jsExtRegExp.test(moduleName)) {
8275 url = (context.config.dir || context.config.dirBaseUrl) + url;
8280 //Override load so that the file paths can be collected.
8281 require.load = function (context, moduleName, url) {
8282 /*jslint evil: true */
8283 var contents, pluginBuilderMatch, builderName;
8285 context.scriptCount += 1;
8287 //Only handle urls that can be inlined, so that means avoiding some
8288 //URLs like ones that require network access or may be too dynamic,
8290 if (require._isSupportedBuildUrl(url)) {
8291 //Adjust the URL if it was not transformed to use baseUrl.
8292 url = normalizeUrlWithBase(context, moduleName, url);
8294 //Save the module name to path and path to module name mappings.
8295 layer.buildPathMap[moduleName] = url;
8296 layer.buildFileToModule[url] = moduleName;
8298 if (moduleName in context.plugins) {
8299 //plugins need to have their source evaled as-is.
8300 context.needFullExec[moduleName] = true;
8304 if (url in require._cachedFileContents &&
8305 (!context.needFullExec[moduleName] || context.fullExec[moduleName])) {
8306 contents = require._cachedFileContents[url];
8308 //Load the file contents, process for conditionals, then
8310 contents = file.readFile(url);
8312 //If there is a read filter, run it now.
8313 if (context.config.onBuildRead) {
8314 contents = context.config.onBuildRead(moduleName, url, contents);
8317 contents = pragma.process(url, contents, context.config, 'OnExecute');
8319 //Find out if the file contains a require() definition. Need to know
8320 //this so we can inject plugins right after it, but before they are needed,
8321 //and to make sure this file is first, so that define calls work.
8322 //This situation mainly occurs when the build is done on top of the output
8323 //of another build, where the first build may include require somewhere in it.
8325 if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) {
8326 layer.existingRequireUrl = url;
8329 throw new Error('Parse error using UglifyJS ' +
8330 'for file: ' + url + '\n' + e1);
8333 if (moduleName in context.plugins) {
8334 //This is a loader plugin, check to see if it has a build extension,
8335 //otherwise the plugin will act as the plugin builder too.
8336 pluginBuilderMatch = pluginBuilderRegExp.exec(contents);
8337 if (pluginBuilderMatch) {
8338 //Load the plugin builder for the plugin contents.
8339 builderName = context.normalize(pluginBuilderMatch[3], moduleName);
8340 contents = file.readFile(context.nameToUrl(builderName));
8344 //Parse out the require and define calls.
8345 //Do this even for plugins in case they have their own
8346 //dependencies that may be separate to how the pluginBuilder works.
8348 if (!context.needFullExec[moduleName]) {
8349 contents = parse(moduleName, url, contents, {
8350 insertNeedsDefine: true,
8351 has: context.config.has,
8352 findNestedDependencies: context.config.findNestedDependencies
8356 throw new Error('Parse error using UglifyJS ' +
8357 'for file: ' + url + '\n' + e2);
8360 require._cachedFileContents[url] = contents;
8367 //Need to close out completion of this module
8368 //so that listeners will get notified that it is available.
8370 context.completeLoad(moduleName);
8372 //Track which module could not complete loading.
8373 (e.moduleTree || (e.moduleTree = [])).push(moduleName);
8378 if (!eOuter.fileName) {
8379 eOuter.fileName = url;
8384 //With unsupported URLs still need to call completeLoad to
8386 context.completeLoad(moduleName);
8389 //Mark the module loaded.
8390 context.loaded[moduleName] = true;
8394 //Called when execManager runs for a dependency. Used to figure out
8395 //what order of execution.
8396 require.onResourceLoad = function (context, map) {
8397 var fullName = map.fullName,
8400 //Ignore "fake" modules, usually generated by plugin code, since
8401 //they do not map back to a real file to include in the optimizer,
8402 //or it will be included, but in a different form.
8403 if (context.fake[fullName]) {
8409 if (!layer.pathAdded[fullName]) {
8410 layer.buildFilePaths.push(fullName);
8411 //For plugins the real path is not knowable, use the name
8412 //for both module to file and file to module mappings.
8413 layer.buildPathMap[fullName] = fullName;
8414 layer.buildFileToModule[fullName] = fullName;
8415 layer.modulesWithNames[fullName] = true;
8416 layer.pathAdded[fullName] = true;
8418 } else if (map.url && require._isSupportedBuildUrl(map.url)) {
8419 //If the url has not been added to the layer yet, and it
8420 //is from an actual file that was loaded, add it now.
8421 url = normalizeUrlWithBase(context, map.fullName, map.url);
8422 if (!layer.pathAdded[url] && layer.buildPathMap[fullName]) {
8423 //Remember the list of dependencies for this layer.
8424 layer.buildFilePaths.push(url);
8425 layer.pathAdded[url] = true;
8430 //Called by output of the parse() function, when a file does not
8431 //explicitly call define, probably just require, but the parse()
8432 //function normalizes on define() for dependency mapping and file
8433 //ordering works correctly.
8434 require.needsDefine = function (moduleName) {
8435 layer.needsDefine[moduleName] = true;
8438 //Marks module has having a name, and optionally executes the
8439 //callback, but only if it meets certain criteria.
8440 require.execCb = function (name, cb, args, exports) {
8441 if (!layer.needsDefine[name]) {
8442 layer.modulesWithNames[name] = true;
8444 if (cb.__requireJsBuild || layer.context.needFullExec[name]) {
8445 return cb.apply(exports, args);
8452 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
8453 * Available via the MIT or new BSD license.
8454 * see: http://github.com/jrburke/requirejs for details
8457 /*jslint plusplus: false, regexp: false, strict: false */
8458 /*global define: false, console: false */
8460 define('commonJs', ['env!env/file', 'uglifyjs/index'], function (file, uglify) {
8462 depRegExp: /require\s*\(\s*["']([\w-_\.\/]+)["']\s*\)/g,
8464 //Set this to false in non-rhino environments. If rhino, then it uses
8465 //rhino's decompiler to remove comments before looking for require() calls,
8466 //otherwise, it will use a crude regexp approach to remove comments. The
8467 //rhino way is more robust, but he regexp is more portable across environments.
8470 //Set to false if you do not want this file to log. Useful in environments
8471 //like node where you want the work to happen without noise.
8474 convertDir: function (commonJsPath, savePath) {
8476 jsFileRegExp = /\.js$/,
8477 fileName, convertedFileName, fileContents;
8479 //Get list of files to convert.
8480 fileList = file.getFilteredFileList(commonJsPath, /\w/, true);
8482 //Normalize on front slashes and make sure the paths do not end in a slash.
8483 commonJsPath = commonJsPath.replace(/\\/g, "/");
8484 savePath = savePath.replace(/\\/g, "/");
8485 if (commonJsPath.charAt(commonJsPath.length - 1) === "/") {
8486 commonJsPath = commonJsPath.substring(0, commonJsPath.length - 1);
8488 if (savePath.charAt(savePath.length - 1) === "/") {
8489 savePath = savePath.substring(0, savePath.length - 1);
8492 //Cycle through all the JS files and convert them.
8493 if (!fileList || !fileList.length) {
8494 if (commonJs.useLog) {
8495 if (commonJsPath === "convert") {
8496 //A request just to convert one file.
8497 console.log('\n\n' + commonJs.convert(savePath, file.readFile(savePath)));
8499 console.log("No files to convert in directory: " + commonJsPath);
8503 for (i = 0; (fileName = fileList[i]); i++) {
8504 convertedFileName = fileName.replace(commonJsPath, savePath);
8507 if (jsFileRegExp.test(fileName)) {
8508 fileContents = file.readFile(fileName);
8509 fileContents = commonJs.convert(fileName, fileContents);
8510 file.saveUtf8File(convertedFileName, fileContents);
8512 //Just copy the file over.
8513 file.copyFile(fileName, convertedFileName, true);
8520 * Removes the comments from a string.
8522 * @param {String} fileContents
8523 * @param {String} fileName mostly used for informative reasons if an error.
8525 * @returns {String} a string of JS with comments removed.
8527 removeComments: function (fileContents, fileName) {
8528 //Uglify's ast generation removes comments, so just convert to ast,
8529 //then back to source code to get rid of comments.
8530 return uglify.uglify.gen_code(uglify.parser.parse(fileContents), true);
8534 * Regexp for testing if there is already a require.def call in the file,
8535 * in which case do not try to convert it.
8537 defRegExp: /define\s*\(\s*("|'|\[|function)/,
8540 * Regexp for testing if there is a require([]) or require(function(){})
8541 * call, indicating the file is already in requirejs syntax.
8543 rjsRegExp: /require\s*\(\s*(\[|function)/,
8546 * Does the actual file conversion.
8548 * @param {String} fileName the name of the file.
8550 * @param {String} fileContents the contents of a file :)
8552 * @param {Boolean} skipDeps if true, require("") dependencies
8553 * will not be searched, but the contents will just be wrapped in the
8554 * standard require, exports, module dependencies. Only usable in sync
8555 * environments like Node where the require("") calls can be resolved on
8558 * @returns {String} the converted contents
8560 convert: function (fileName, fileContents, skipDeps) {
8561 //Strip out comments.
8563 var deps = [], depName, match,
8565 tempContents = commonJs.removeComments(fileContents, fileName);
8567 //First see if the module is not already RequireJS-formatted.
8568 if (commonJs.defRegExp.test(tempContents) || commonJs.rjsRegExp.test(tempContents)) {
8569 return fileContents;
8572 //Reset the regexp to start at beginning of file. Do this
8573 //since the regexp is reused across files.
8574 commonJs.depRegExp.lastIndex = 0;
8577 //Find dependencies in the code that was not in comments.
8578 while ((match = commonJs.depRegExp.exec(tempContents))) {
8581 deps.push('"' + depName + '"');
8586 //Construct the wrapper boilerplate.
8587 fileContents = 'define(["require", "exports", "module"' +
8588 (deps.length ? ', ' + deps.join(",") : '') + '], ' +
8589 'function(require, exports, module) {\n' +
8593 console.log("COULD NOT CONVERT: " + fileName + ", so skipping it. Error was: " + e);
8594 return fileContents;
8597 return fileContents;
8604 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
8605 * Available via the MIT or new BSD license.
8606 * see: http://github.com/jrburke/requirejs for details
8609 /*jslint plusplus: true, nomen: true */
8610 /*global define, require */
8613 define('build', [ 'lang', 'logger', 'env!env/file', 'parse', 'optimize', 'pragma',
8614 'env!env/load', 'requirePatch'],
8615 function (lang, logger, file, parse, optimize, pragma,
8616 load, requirePatch) {
8619 var build, buildBaseConfig,
8620 endsWithSemiColonRegExp = /;\s*$/;
8627 optimizeCss: "standard.keepLines",
8630 optimizeAllPluginResources: false,
8631 findNestedDependencies: false,
8632 preserveLicenseComments: true,
8633 //By default, all files/directories are copied, unless
8634 //they match this regexp, by default just excludes .folders
8635 dirExclusionRegExp: file.dirExclusionRegExp
8639 * Some JS may not be valid if concatenated with other JS, in particular
8640 * the style of omitting semicolons and rely on ASI. Add a semicolon in
8643 function addSemiColon(text) {
8644 if (endsWithSemiColonRegExp.test(text)) {
8652 * If the path looks like an URL, throw an error. This is to prevent
8653 * people from using URLs with protocols in the build config, since
8654 * the optimizer is not set up to do network access. However, be
8655 * sure to allow absolute paths on Windows, like C:\directory.
8657 function disallowUrls(path) {
8658 if ((path.indexOf('://') !== -1 || path.indexOf('//') === 0) && path !== 'empty:') {
8659 throw new Error('Path is not supported: ' + path +
8660 '\nOptimizer can only handle' +
8661 ' local paths. Download the locally if necessary' +
8662 ' and update the config to use a local path.\n' +
8663 'http://requirejs.org/docs/errors.html#pathnotsupported');
8667 function endsWithSlash(dirName) {
8668 if (dirName.charAt(dirName.length - 1) !== "/") {
8671 disallowUrls(dirName);
8675 //Method used by plugin writeFile calls, defined up here to avoid
8676 //jslint warning about "making a function in a loop".
8677 function makeWriteFile(anonDefRegExp, namespaceWithDot, layer) {
8678 function writeFile(name, contents) {
8679 logger.trace('Saving plugin-optimized file: ' + name);
8680 file.saveUtf8File(name, contents);
8683 writeFile.asModule = function (moduleName, fileName, contents) {
8685 build.toTransport(anonDefRegExp, namespaceWithDot, moduleName, fileName, contents, layer));
8692 * Main API entry point into the build. The args argument can either be
8693 * an array of arguments (like the onese passed on a command-line),
8694 * or it can be a JavaScript object that has the format of a build profile
8697 * If it is an object, then in addition to the normal properties allowed in
8698 * a build profile file, the object should contain one other property:
8700 * The object could also contain a "buildFile" property, which is a string
8701 * that is the file path to a build profile that contains the rest
8702 * of the build profile directives.
8704 * This function does not return a status, it should throw an error if
8705 * there is a problem completing the build.
8707 build = function (args) {
8708 var buildFile, cmdConfig;
8710 if (!args || lang.isArray(args)) {
8711 if (!args || args.length < 1) {
8712 logger.error("build.js buildProfile.js\n" +
8713 "where buildProfile.js is the name of the build file (see example.build.js for hints on how to make a build file).");
8717 //Next args can include a build file path as well as other build args.
8718 //build file path comes first. If it does not contain an = then it is
8719 //a build file path. Otherwise, just all build args.
8720 if (args[0].indexOf("=") === -1) {
8721 buildFile = args[0];
8725 //Remaining args are options to the build
8726 cmdConfig = build.convertArrayToObject(args);
8727 cmdConfig.buildFile = buildFile;
8732 return build._run(cmdConfig);
8735 build._run = function (cmdConfig) {
8736 var buildFileContents = "",
8737 pluginCollector = {},
8738 buildPaths, fileName, fileNames,
8741 modules, builtModule, srcPath, buildContext,
8742 destPath, moduleName, moduleMap, parentModuleMap, context,
8743 resources, resource, pluginProcessed = {}, plugin;
8745 //Can now run the patches to require.js to allow it to be used for
8746 //build generation. Do it here instead of at the top of the module
8747 //because we want normal require behavior to load the build tool
8748 //then want to switch to build mode.
8751 config = build.createConfig(cmdConfig);
8752 paths = config.paths;
8754 if (config.logLevel) {
8755 logger.logLevel(config.logLevel);
8758 if (!config.out && !config.cssIn) {
8759 //This is not just a one-off file build but a full build profile, with
8760 //lots of files to process.
8762 //First copy all the baseUrl content
8763 file.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true);
8765 //Adjust baseUrl if config.appDir is in play, and set up build output paths.
8767 if (config.appDir) {
8768 //All the paths should be inside the appDir, so just adjust
8769 //the paths to use the dirBaseUrl
8770 for (prop in paths) {
8771 if (paths.hasOwnProperty(prop)) {
8772 buildPaths[prop] = paths[prop].replace(config.baseUrl, config.dirBaseUrl);
8776 //If no appDir, then make sure to copy the other paths to this directory.
8777 for (prop in paths) {
8778 if (paths.hasOwnProperty(prop)) {
8779 //Set up build path for each path prefix.
8780 buildPaths[prop] = paths[prop] === 'empty:' ? 'empty:' : prop.replace(/\./g, "/");
8782 //Make sure source path is fully formed with baseUrl,
8783 //if it is a relative URL.
8784 srcPath = paths[prop];
8785 if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) {
8786 srcPath = config.baseUrl + srcPath;
8789 destPath = config.dirBaseUrl + buildPaths[prop];
8792 if (srcPath !== 'empty:') {
8793 //If the srcPath is a directory, copy the whole directory.
8794 if (file.exists(srcPath) && file.isDirectory(srcPath)) {
8795 //Copy files to build area. Copy all files (the /\w/ regexp)
8796 file.copyDir(srcPath, destPath, /\w/, true);
8798 //Try a .js extension
8801 file.copyFile(srcPath, destPath);
8809 //Figure out source file location for each module layer. Do this by seeding require
8810 //with source area configuration. This is needed so that later the module layers
8811 //can be manually copied over to the source area, since the build may be
8812 //require multiple times and the above copyDir call only copies newer files.
8814 baseUrl: config.baseUrl,
8816 packagePaths: config.packagePaths,
8817 packages: config.packages
8819 buildContext = require.s.contexts._;
8820 modules = config.modules;
8823 modules.forEach(function (module) {
8825 module._sourcePath = buildContext.nameToUrl(module.name);
8826 //If the module does not exist, and this is not a "new" module layer,
8827 //as indicated by a true "create" property on the module, and
8828 //it is not a plugin-loaded resource, then throw an error.
8829 if (!file.exists(module._sourcePath) && !module.create &&
8830 module.name.indexOf('!') === -1) {
8831 throw new Error("ERROR: module path does not exist: " +
8832 module._sourcePath + " for module named: " + module.name +
8833 ". Path is relative to: " + file.absPath('.'));
8840 //Just set up the _buildPath for the module layer.
8842 if (!config.cssIn) {
8843 config.modules[0]._buildPath = config.out;
8845 } else if (!config.cssIn) {
8846 //Now set up the config for require to use the build area, and calculate the
8847 //build file locations. Pass along any config info too.
8849 baseUrl: config.dirBaseUrl,
8853 lang.mixin(baseConfig, config);
8854 require(baseConfig);
8857 modules.forEach(function (module) {
8859 module._buildPath = buildContext.nameToUrl(module.name, null);
8860 if (!module.create) {
8861 file.copyFile(module._sourcePath, module._buildPath);
8868 //Run CSS optimizations before doing JS module tracing, to allow
8869 //things like text loader plugins loading CSS to get the optimized
8871 if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) {
8872 buildFileContents += optimize.css(config.dir, config);
8876 //For each module layer, call require to calculate dependencies.
8877 modules.forEach(function (module) {
8878 module.layer = build.traceDependencies(module, config);
8881 //Now build up shadow layers for anything that should be excluded.
8882 //Do this after tracing dependencies for each module, in case one
8883 //of those modules end up being one of the excluded values.
8884 modules.forEach(function (module) {
8885 if (module.exclude) {
8886 module.excludeLayers = [];
8887 module.exclude.forEach(function (exclude, i) {
8888 //See if it is already in the list of modules.
8889 //If not trace dependencies for it.
8890 module.excludeLayers[i] = build.findBuildModule(exclude, modules) ||
8891 {layer: build.traceDependencies({name: exclude}, config)};
8896 modules.forEach(function (module) {
8897 if (module.exclude) {
8898 //module.exclude is an array of module names. For each one,
8899 //get the nested dependencies for it via a matching entry
8900 //in the module.excludeLayers array.
8901 module.exclude.forEach(function (excludeModule, i) {
8902 var excludeLayer = module.excludeLayers[i].layer, map = excludeLayer.buildPathMap, prop;
8904 if (map.hasOwnProperty(prop)) {
8905 build.removeModulePath(prop, map[prop], module.layer);
8910 if (module.excludeShallow) {
8911 //module.excludeShallow is an array of module names.
8912 //shallow exclusions are just that module itself, and not
8913 //its nested dependencies.
8914 module.excludeShallow.forEach(function (excludeShallowModule) {
8915 var path = module.layer.buildPathMap[excludeShallowModule];
8917 build.removeModulePath(excludeShallowModule, path, module.layer);
8922 //Flatten them and collect the build output for each module.
8923 builtModule = build.flattenModule(module, module.layer, config);
8925 //Save it to a temp file for now, in case there are other layers that
8926 //contain optimized content that should not be included in later
8927 //layer optimizations. See issue #56.
8928 file.saveUtf8File(module._buildPath + '-temp', builtModule.text);
8929 buildFileContents += builtModule.buildText;
8932 //Now move the build layers to their final position.
8933 modules.forEach(function (module) {
8934 var finalPath = module._buildPath;
8935 if (file.exists(finalPath)) {
8936 file.deleteFile(finalPath);
8938 file.renameFile(finalPath + '-temp', finalPath);
8942 //Do other optimizations.
8943 if (config.out && !config.cssIn) {
8944 //Just need to worry about one JS file.
8945 fileName = config.modules[0]._buildPath;
8946 optimize.jsFile(fileName, fileName, config);
8947 } else if (!config.cssIn) {
8948 //Normal optimizations across modules.
8951 fileNames = file.getFilteredFileList(config.dir, /\.js$/, true);
8952 for (i = 0; (fileName = fileNames[i]); i++) {
8953 //Generate the module name from the config.dir root.
8954 moduleName = fileName.replace(config.dir, '');
8955 //Get rid of the extension
8956 moduleName = moduleName.substring(0, moduleName.length - 3);
8957 optimize.jsFile(fileName, fileName, config, moduleName, pluginCollector);
8960 //Normalize all the plugin resources.
8961 context = require.s.contexts._;
8963 for (moduleName in pluginCollector) {
8964 if (pluginCollector.hasOwnProperty(moduleName)) {
8965 parentModuleMap = context.makeModuleMap(moduleName);
8966 resources = pluginCollector[moduleName];
8967 for (i = 0; (resource = resources[i]); i++) {
8968 moduleMap = context.makeModuleMap(resource, parentModuleMap);
8969 if (!context.plugins[moduleMap.prefix]) {
8970 //Set the value in context.plugins so it
8971 //will be evaluated as a full plugin.
8972 context.plugins[moduleMap.prefix] = true;
8974 //Do not bother if the plugin is not available.
8975 if (!file.exists(require.toUrl(moduleMap.prefix + '.js'))) {
8979 //Rely on the require in the build environment
8981 context.require([moduleMap.prefix]);
8983 //Now that the plugin is loaded, redo the moduleMap
8984 //since the plugin will need to normalize part of the path.
8985 moduleMap = context.makeModuleMap(resource, parentModuleMap);
8988 //Only bother with plugin resources that can be handled
8989 //processed by the plugin, via support of the writeFile
8991 if (!pluginProcessed[moduleMap.fullName]) {
8992 //Only do the work if the plugin was really loaded.
8993 //Using an internal access because the file may
8994 //not really be loaded.
8995 plugin = context.defined[moduleMap.prefix];
8996 if (plugin && plugin.writeFile) {
9002 config.anonDefRegExp,
9003 config.namespaceWithDot
9009 pluginProcessed[moduleMap.fullName] = true;
9016 //console.log('PLUGIN COLLECTOR: ' + JSON.stringify(pluginCollector, null, " "));
9019 //All module layers are done, write out the build.txt file.
9020 file.saveUtf8File(config.dir + "build.txt", buildFileContents);
9023 //If just have one CSS file to optimize, do that here.
9025 buildFileContents += optimize.cssFile(config.cssIn, config.out, config);
9028 //Print out what was built into which layers.
9029 if (buildFileContents) {
9030 logger.info(buildFileContents);
9031 return buildFileContents;
9038 * Converts command line args like "paths.foo=../some/path"
9039 * result.paths = { foo: '../some/path' } where prop = paths,
9040 * name = paths.foo and value = ../some/path, so it assumes the
9041 * name=value splitting has already happened.
9043 function stringDotToObj(result, prop, name, value) {
9044 if (!result[prop]) {
9047 name = name.substring((prop + '.').length, name.length);
9048 result[prop][name] = value;
9051 //Used by convertArrayToObject to convert some things from prop.name=value
9052 //to a prop: { name: value}
9065 build.hasDotPropMatch = function (prop) {
9066 return build.dotProps.some(function (dotProp) {
9067 return prop.indexOf(dotProp) === 0;
9072 * Converts an array that has String members of "name=value"
9073 * into an object, where the properties on the object are the names in the array.
9074 * Also converts the strings "true" and "false" to booleans for the values.
9075 * member name/value pairs, and converts some comma-separated lists into
9077 * @param {Array} ary
9079 build.convertArrayToObject = function (ary) {
9080 var result = {}, i, separatorIndex, prop, value,
9084 "excludeShallow": true
9087 for (i = 0; i < ary.length; i++) {
9088 separatorIndex = ary[i].indexOf("=");
9089 if (separatorIndex === -1) {
9090 throw "Malformed name/value pair: [" + ary[i] + "]. Format should be name=value";
9093 value = ary[i].substring(separatorIndex + 1, ary[i].length);
9094 if (value === "true") {
9096 } else if (value === "false") {
9100 prop = ary[i].substring(0, separatorIndex);
9102 //Convert to array if necessary
9103 if (needArray[prop]) {
9104 value = value.split(",");
9107 if (build.hasDotPropMatch(prop)) {
9108 stringDotToObj(result, prop.split('.')[0], prop, value);
9110 result[prop] = value;
9113 return result; //Object
9116 build.makeAbsPath = function (path, absFilePath) {
9117 //Add abspath if necessary. If path starts with a slash or has a colon,
9118 //then already is an abolute path.
9119 if (path.indexOf('/') !== 0 && path.indexOf(':') === -1) {
9120 path = absFilePath +
9121 (absFilePath.charAt(absFilePath.length - 1) === '/' ? '' : '/') +
9123 path = file.normalize(path);
9125 return path.replace(lang.backSlashRegExp, '/');
9128 build.makeAbsObject = function (props, obj, absFilePath) {
9131 for (i = 0; (prop = props[i]); i++) {
9132 if (obj.hasOwnProperty(prop)) {
9133 obj[prop] = build.makeAbsPath(obj[prop], absFilePath);
9140 * For any path in a possible config, make it absolute relative
9141 * to the absFilePath passed in.
9143 build.makeAbsConfig = function (config, absFilePath) {
9146 props = ["appDir", "dir", "baseUrl"];
9147 for (i = 0; (prop = props[i]); i++) {
9149 //Add abspath if necessary, make sure these paths end in
9151 if (prop === "baseUrl") {
9152 config.originalBaseUrl = config.baseUrl;
9153 if (config.appDir) {
9154 //If baseUrl with an appDir, the baseUrl is relative to
9155 //the appDir, *not* the absFilePath. appDir and dir are
9156 //made absolute before baseUrl, so this will work.
9157 config.baseUrl = build.makeAbsPath(config.originalBaseUrl, config.appDir);
9159 //The dir output baseUrl is same as regular baseUrl, both
9160 //relative to the absFilePath.
9161 config.baseUrl = build.makeAbsPath(config[prop], absFilePath);
9164 config[prop] = build.makeAbsPath(config[prop], absFilePath);
9167 config[prop] = endsWithSlash(config[prop]);
9171 //Do not allow URLs for paths resources.
9173 for (prop in config.paths) {
9174 if (config.paths.hasOwnProperty(prop)) {
9175 config.paths[prop] = build.makeAbsPath(config.paths[prop],
9176 (config.baseUrl || absFilePath));
9181 build.makeAbsObject(["out", "cssIn"], config, absFilePath);
9182 build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath);
9194 * Mixes additional source config into target config, and merges some
9195 * nested config, like paths, correctly.
9197 function mixConfig(target, source) {
9200 for (prop in source) {
9201 if (source.hasOwnProperty(prop)) {
9202 //If the value of the property is a plain object, then
9203 //allow a one-level-deep mixing of it.
9204 value = source[prop];
9205 if (typeof value === 'object' && value &&
9206 !lang.isArray(value) && !lang.isFunction(value) &&
9207 !lang.isRegExp(value)) {
9208 target[prop] = lang.mixin({}, target[prop], value, true);
9210 target[prop] = value;
9217 * Creates a config object for an optimization build.
9218 * It will also read the build profile if it is available, to create
9219 * the configuration.
9221 * @param {Object} cfg config options that take priority
9222 * over defaults and ones in the build file. These options could
9223 * be from a command line, for instance.
9225 * @param {Object} the created config object.
9227 build.createConfig = function (cfg) {
9228 /*jslint evil: true */
9229 var config = {}, buildFileContents, buildFileConfig, mainConfig,
9230 mainConfigFile, prop, buildFile, absFilePath;
9232 //Make sure all paths are relative to current directory.
9233 absFilePath = file.absPath('.');
9234 build.makeAbsConfig(cfg, absFilePath);
9235 build.makeAbsConfig(buildBaseConfig, absFilePath);
9237 lang.mixin(config, buildBaseConfig);
9238 lang.mixin(config, cfg, true);
9240 if (config.buildFile) {
9241 //A build file exists, load it to get more config.
9242 buildFile = file.absPath(config.buildFile);
9244 //Find the build file, and make sure it exists, if this is a build
9245 //that has a build profile, and not just command line args with an in=path
9246 if (!file.exists(buildFile)) {
9247 throw new Error("ERROR: build file does not exist: " + buildFile);
9250 absFilePath = config.baseUrl = file.absPath(file.parent(buildFile));
9252 //Load build file options.
9253 buildFileContents = file.readFile(buildFile);
9255 buildFileConfig = eval("(" + buildFileContents + ")");
9256 build.makeAbsConfig(buildFileConfig, absFilePath);
9258 if (!buildFileConfig.out && !buildFileConfig.dir) {
9259 buildFileConfig.dir = (buildFileConfig.baseUrl || config.baseUrl) + "/build/";
9263 throw new Error("Build file " + buildFile + " is malformed: " + e);
9267 mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile);
9268 if (mainConfigFile) {
9269 mainConfigFile = build.makeAbsPath(mainConfigFile, absFilePath);
9271 mainConfig = parse.findConfig(mainConfigFile, file.readFile(mainConfigFile));
9272 } catch (configError) {
9273 throw new Error('The config in mainConfigFile ' +
9275 ' cannot be used because it cannot be evaluated' +
9276 ' correctly while running in the optimizer. Try only' +
9277 ' using a config that is also valid JSON, or do not use' +
9278 ' mainConfigFile and instead copy the config values needed' +
9279 ' into a build file or command line arguments given to the optimizer.');
9282 //If no baseUrl, then use the directory holding the main config.
9283 if (!mainConfig.baseUrl) {
9284 mainConfig.baseUrl = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/'));
9286 build.makeAbsConfig(mainConfig, mainConfigFile);
9287 mixConfig(config, mainConfig);
9291 //Mix in build file config, but only after mainConfig has been mixed in.
9292 if (buildFileConfig) {
9293 mixConfig(config, buildFileConfig);
9296 //Re-apply the override config values. Command line
9297 //args should take precedence over build file values.
9298 mixConfig(config, cfg);
9301 //Set final output dir
9302 if (config.hasOwnProperty("baseUrl")) {
9303 if (config.appDir) {
9304 config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir);
9306 config.dirBaseUrl = config.dir || config.baseUrl;
9308 //Make sure dirBaseUrl ends in a slash, since it is
9309 //concatenated with other strings.
9310 config.dirBaseUrl = endsWithSlash(config.dirBaseUrl);
9313 //Check for errors in config
9314 if (config.cssIn && !config.out) {
9315 throw new Error("ERROR: 'out' option missing.");
9317 if (!config.cssIn && !config.baseUrl) {
9318 throw new Error("ERROR: 'baseUrl' option missing.");
9320 if (!config.out && !config.dir) {
9321 throw new Error('Missing either an "out" or "dir" config value. ' +
9322 'If using "appDir" for a full project optimization, ' +
9323 'use "dir". If you want to optimize to one file, ' +
9326 if (config.appDir && config.out) {
9327 throw new Error('"appDir" is not compatible with "out". Use "dir" ' +
9328 'instead. appDir is used to copy whole projects, ' +
9329 'where "out" is used to just optimize to one file.');
9331 if (config.out && config.dir) {
9332 throw new Error('The "out" and "dir" options are incompatible.' +
9333 ' Use "out" if you are targeting a single file for' +
9334 ' for optimization, and "dir" if you want the appDir' +
9335 ' or baseUrl directories optimized.');
9338 if ((config.name || config.include) && !config.modules) {
9339 //Just need to build one file, but may be part of a whole appDir/
9340 //baseUrl copy, but specified on the command line, so cannot do
9341 //the modules array setup. So create a modules section in that
9347 include: config.include,
9348 exclude: config.exclude,
9349 excludeShallow: config.excludeShallow
9354 if (config.out && !config.cssIn) {
9355 //Just one file to optimize.
9357 //Does not have a build file, so set up some defaults.
9358 //Optimizing CSS should not be allowed, unless explicitly
9359 //asked for on command line. In that case the only task is
9360 //to optimize a CSS file.
9361 if (!cfg.optimizeCss) {
9362 config.optimizeCss = "none";
9366 //Do not allow URLs for paths resources.
9368 for (prop in config.paths) {
9369 if (config.paths.hasOwnProperty(prop)) {
9370 disallowUrls(config.paths[prop]);
9375 //Get any wrap text.
9378 if (config.wrap === true) {
9379 //Use default values.
9381 start: '(function () {',
9385 config.wrap.start = config.wrap.start ||
9386 file.readFile(build.makeAbsPath(config.wrap.startFile, absFilePath));
9387 config.wrap.end = config.wrap.end ||
9388 file.readFile(build.makeAbsPath(config.wrap.endFile, absFilePath));
9391 } catch (wrapError) {
9392 throw new Error('Malformed wrap config: need both start/end or ' +
9393 'startFile/endFile: ' + wrapError.toString());
9397 //Set up proper info for namespaces and using namespaces in transport
9399 config.namespaceWithDot = config.namespace ? config.namespace + '.' : '';
9400 config.anonDefRegExp = build.makeAnonDefRegExp(config.namespaceWithDot);
9402 //Do final input verification
9403 if (config.context) {
9404 throw new Error('The build argument "context" is not supported' +
9405 ' in a build. It should only be used in web' +
9409 //Set file.fileExclusionRegExp if desired
9410 if ('fileExclusionRegExp' in config) {
9411 if (typeof config.fileExclusionRegExp === "string") {
9412 file.exclusionRegExp = new RegExp(config.fileExclusionRegExp);
9414 file.exclusionRegExp = config.fileExclusionRegExp;
9416 } else if ('dirExclusionRegExp' in config) {
9417 //Set file.dirExclusionRegExp if desired, this is the old
9418 //name for fileExclusionRegExp before 1.0.2. Support for backwards
9420 file.exclusionRegExp = config.dirExclusionRegExp;
9427 * finds the module being built/optimized with the given moduleName,
9429 * @param {String} moduleName
9430 * @param {Array} modules
9431 * @returns {Object} the module object from the build profile, or null.
9433 build.findBuildModule = function (moduleName, modules) {
9435 for (i = 0; (module = modules[i]); i++) {
9436 if (module.name === moduleName) {
9444 * Removes a module name and path from a layer, if it is supposed to be
9445 * excluded from the layer.
9446 * @param {String} moduleName the name of the module
9447 * @param {String} path the file path for the module
9448 * @param {Object} layer the layer to remove the module/path from
9450 build.removeModulePath = function (module, path, layer) {
9451 var index = layer.buildFilePaths.indexOf(path);
9453 layer.buildFilePaths.splice(index, 1);
9456 //Take it out of the specified modules. Specified modules are mostly
9457 //used to find require modifiers.
9458 delete layer.specified[module];
9462 * Uses the module build config object to trace the dependencies for the
9465 * @param {Object} module the module object from the build config info.
9466 * @param {Object} the build config object.
9468 * @returns {Object} layer information about what paths and modules should
9469 * be in the flattened module.
9471 build.traceDependencies = function (module, config) {
9472 var include, override, layer, context, baseConfig, oldContext;
9474 //Reset some state set up in requirePatch.js, and clean up require's
9476 oldContext = require._buildReset();
9478 //Grab the reset layer and context after the reset, but keep the
9479 //old config to reuse in the new context.
9480 baseConfig = oldContext.config;
9481 layer = require._layer;
9482 context = layer.context;
9484 //Put back basic config, use a fresh object for it.
9485 //WARNING: probably not robust for paths and packages/packagePaths,
9486 //since those property's objects can be modified. But for basic
9487 //config clone it works out.
9488 require(lang.delegate(baseConfig));
9490 logger.trace("\nTracing dependencies for: " + (module.name || module.out));
9491 include = module.name && !module.create ? [module.name] : [];
9492 if (module.include) {
9493 include = include.concat(module.include);
9496 //If there are overrides to basic config, set that up now.;
9497 if (module.override) {
9498 override = lang.delegate(baseConfig);
9499 lang.mixin(override, module.override, true);
9503 //Figure out module layer dependencies by calling require to do the work.
9506 //Pull out the layer dependencies.
9507 layer.specified = context.specified;
9510 if (module.override) {
9511 require(baseConfig);
9518 * Uses the module build config object to create an flattened version
9519 * of the module, with deep dependencies included.
9521 * @param {Object} module the module object from the build config info.
9523 * @param {Object} layer the layer object returned from build.traceDependencies.
9525 * @param {Object} the build config object.
9527 * @returns {Object} with two properties: "text", the text of the flattened
9528 * module, and "buildText", a string of text representing which files were
9529 * included in the flattened module text.
9531 build.flattenModule = function (module, layer, config) {
9532 var buildFileContents = "",
9533 namespace = config.namespace ? config.namespace + '.' : '',
9534 context = layer.context,
9535 anonDefRegExp = config.anonDefRegExp,
9536 path, reqIndex, fileContents, currContents,
9538 parts, builder, writeApi;
9540 //Use override settings, particularly for pragmas
9541 if (module.override) {
9542 config = lang.delegate(config);
9543 lang.mixin(config, module.override, true);
9546 //Start build output for the module.
9547 buildFileContents += "\n" +
9548 (config.dir ? module._buildPath.replace(config.dir, "") : module._buildPath) +
9549 "\n----------------\n";
9551 //If there was an existing file with require in it, hoist to the top.
9552 if (layer.existingRequireUrl) {
9553 reqIndex = layer.buildFilePaths.indexOf(layer.existingRequireUrl);
9554 if (reqIndex !== -1) {
9555 layer.buildFilePaths.splice(reqIndex, 1);
9556 layer.buildFilePaths.unshift(layer.existingRequireUrl);
9560 //Write the built module to disk, and build up the build output.
9562 for (i = 0; (path = layer.buildFilePaths[i]); i++) {
9563 moduleName = layer.buildFileToModule[path];
9565 //Figure out if the module is a result of a build plugin, and if so,
9566 //then delegate to that plugin.
9567 parts = context.makeModuleMap(moduleName);
9568 builder = parts.prefix && context.defined[parts.prefix];
9570 if (builder.write) {
9571 writeApi = function (input) {
9572 fileContents += "\n" + addSemiColon(input);
9573 if (config.onBuildWrite) {
9574 fileContents = config.onBuildWrite(moduleName, path, fileContents);
9577 writeApi.asModule = function (moduleName, input) {
9578 fileContents += "\n" +
9580 build.toTransport(anonDefRegExp, namespace, moduleName, path, input, layer));
9581 if (config.onBuildWrite) {
9582 fileContents = config.onBuildWrite(moduleName, path, fileContents);
9585 builder.write(parts.prefix, parts.name, writeApi);
9588 currContents = file.readFile(path);
9590 if (config.onBuildRead) {
9591 currContents = config.onBuildRead(moduleName, path, currContents);
9594 if (config.namespace) {
9595 currContents = pragma.namespace(currContents, config.namespace);
9598 currContents = build.toTransport(anonDefRegExp, namespace, moduleName, path, currContents, layer);
9600 if (config.onBuildWrite) {
9601 currContents = config.onBuildWrite(moduleName, path, currContents);
9604 //Semicolon is for files that are not well formed when
9605 //concatenated with other content.
9606 fileContents += "\n" + addSemiColon(currContents);
9609 buildFileContents += path.replace(config.dir, "") + "\n";
9610 //Some files may not have declared a require module, and if so,
9611 //put in a placeholder call so the require does not try to load them
9612 //after the module is processed.
9613 //If we have a name, but no defined module, then add in the placeholder.
9614 if (moduleName && !layer.modulesWithNames[moduleName] && !config.skipModuleInsertion) {
9615 //If including jquery, register the module correctly, otherwise
9616 //register an empty function. For jquery, make sure jQuery is
9617 //a real object, and perhaps not some other file mapping, like
9619 if (moduleName === 'jquery') {
9620 fileContents += '\n(function () {\n' +
9621 'var jq = typeof jQuery !== "undefined" && jQuery;\n' +
9623 'define("jquery", [], function () { return jq; });\n' +
9626 fileContents += '\n' + namespace + 'define("' + moduleName + '", function(){});\n';
9633 config.wrap.start + fileContents + config.wrap.end :
9635 buildText: buildFileContents
9640 * Creates the regexp to find anonymous defines.
9641 * @param {String} namespace an optional namespace to use. The namespace
9642 * should *include* a trailing dot. So a valid value would be 'foo.'
9645 build.makeAnonDefRegExp = function (namespace) {
9646 //This regexp is not bullet-proof, and it has one optional part to
9647 //avoid issues with some Dojo transition modules that use a
9648 //define(\n//begin v1.x content
9650 return new RegExp('(^|[^\\.])(' + (namespace || '').replace(/\./g, '\\.') +
9651 'define|define)\\s*\\(\\s*(\\/\\/[^\\n\\r]*[\\r\\n])?(\\[|function|[\\w\\d_\\-\\$]+\\s*\\)|\\{|["\']([^"\']+)["\'])(\\s*,\\s*f)?');
9654 build.leadingCommaRegExp = /^\s*,/;
9656 build.toTransport = function (anonDefRegExp, namespace, moduleName, path, contents, layer) {
9658 //If anonymous module, insert the module name.
9659 return contents.replace(anonDefRegExp, function (match, start, callName, possibleComment, suffix, namedModule, namedFuncStart) {
9660 //A named module with either listed dependencies or an object
9661 //literal for a value. Skip it. If named module, only want ones
9662 //whose next argument is a function literal to scan for
9663 //require('') dependecies.
9664 if (namedModule && !namedFuncStart) {
9668 //Only mark this module as having a name if not a named module,
9669 //or if a named module and the name matches expectations.
9670 if (layer && (!namedModule || namedModule === moduleName)) {
9671 layer.modulesWithNames[moduleName] = true;
9676 //Look for CommonJS require calls inside the function if this is
9677 //an anonymous define call that just has a function registered.
9678 //Also look if a named define function but has a factory function
9679 //as the second arg that should be scanned for dependencies.
9680 if (suffix.indexOf('f') !== -1 || (namedModule)) {
9681 deps = parse.getAnonDeps(path, contents);
9684 deps = deps.map(function (dep) {
9685 return "'" + dep + "'";
9692 return start + namespace + "define('" + (namedModule || moduleName) + "'," +
9693 (deps ? ('[' + deps.toString() + '],') : '') +
9694 (namedModule ? namedFuncStart.replace(build.leadingCommaRegExp, '') : suffix);
9706 * Sets the default baseUrl for requirejs to be directory of top level
9709 function setBaseUrl(fileName) {
9710 //Use the file name's directory as the baseUrl if available.
9711 dir = fileName.replace(/\\/g, '/');
9712 if (dir.indexOf('/') !== -1) {
9713 dir = dir.split('/');
9715 dir = dir.join('/');
9716 exec("require({baseUrl: '" + dir + "'});");
9720 //If in Node, and included via a require('requirejs'), just export and
9721 //THROW IT ON THE GROUND!
9722 if (env === 'node' && reqMain !== module) {
9723 setBaseUrl(path.resolve(reqMain ? reqMain.filename : '.'));
9725 //Create a method that will run the optimzer given an object
9727 requirejs.optimize = function (config, callback) {
9728 if (!loadedOptimizedLib) {
9730 loadedOptimizedLib = true;
9733 //Create the function that will be called once build modules
9735 var runBuild = function (build, logger) {
9736 //Make sure config has a log level, and if not,
9737 //make it "silent" by default.
9738 config.logLevel = config.hasOwnProperty('logLevel') ?
9739 config.logLevel : logger.SILENT;
9741 var result = build(config);
9743 //Reset build internals on each run.
9744 requirejs._buildReset();
9751 //Enable execution of this callback in a build setting.
9752 //Normally, once requirePatch is run, by default it will
9753 //not execute callbacks, unless this property is set on
9755 runBuild.__requireJsBuild = true;
9759 }, ['build', 'logger'], runBuild);
9763 useLib: function (contextName, callback) {
9765 callback = contextName;
9766 contextName = 'uselib';
9769 if (!useLibLoaded[contextName]) {
9771 useLibLoaded[contextName] = true;
9774 var req = requirejs({
9775 context: contextName,
9776 requireLoad: requirejsVars.nodeLoad,
9777 requireExecCb: requirejsVars.nodeRequireExecCb
9780 req(['build'], function () {
9786 requirejs.define = define;
9788 module.exports = requirejs;
9792 if (commandOption === 'o') {
9793 //Do the optimizer work.
9797 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
9798 * Available via the MIT or new BSD license.
9799 * see: http://github.com/jrburke/requirejs for details
9803 * Create a build.js file that has the build options you want and pass that
9804 * build file to this file to do the build. See example.build.js for more information.
9807 /*jslint strict: false, nomen: false */
9808 /*global require: false */
9811 baseUrl: require.s.contexts._.config.baseUrl,
9812 //Use a separate context than the default context so that the
9813 //build can use the default context.
9818 }, ['env!env/args', 'build'],
9819 function (args, build) {
9824 } else if (commandOption === 'v') {
9825 console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version);
9826 } else if (commandOption === 'convert') {
9829 this.requirejsVars.require(['env!env/args', 'commonJs', 'env!env/print'],
9830 function (args, commonJs, print) {
9836 if (!srcDir || !outDir) {
9837 print('Usage: path/to/commonjs/modules output/dir');
9841 commonJs.convertDir(args[0], args[1]);
9846 //Load the bundled libraries for use in the app.
9847 if (commandOption === 'lib') {
9851 setBaseUrl(fileName);
9853 if (exists(fileName)) {
9854 exec(readFile(fileName), fileName);
9860 }((typeof console !== 'undefined' ? console : undefined),
9861 (typeof Packages !== 'undefined' ? Array.prototype.slice.call(arguments, 0) : []),
9862 (typeof readFile !== 'undefined' ? readFile : undefined)));