2 * @license r.js 2.1.8+ Tue, 13 Aug 2013 02:54:07 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, sloppy: true */
15 /*global readFile: true, process: false, Packages: false, print: false,
16 console: false, java: false, module: false, requirejsVars, navigator,
17 document, importScripts, self, location, Components, FileUtils */
19 var requirejs, require, define, xpcUtil;
20 (function (console, args, readFileFunc) {
21 var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire,
22 nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci,
23 version = '2.1.8+ Tue, 13 Aug 2013 02:54:07 GMT',
24 jsSuffixRegExp = /\.js$/,
27 //Used by jslib/rhino/args.js
29 //Used by jslib/xpconnect/args.js
31 readFile = typeof readFileFunc !== 'undefined' ? readFileFunc : null;
34 console.log('See https://github.com/jrburke/r.js for usage.');
37 if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') ||
38 (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) {
41 readFile = function (path) {
42 return fs.readFileSync(path, 'utf8');
45 exec = function (string) {
49 exists = function () {
50 console.log('x.js exists not applicable in browser env');
54 } else if (typeof Packages !== 'undefined') {
59 if (fileName && fileName.indexOf('-') === 0) {
60 commandOption = fileName.substring(1);
64 //Set up execution context.
65 rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext();
67 exec = function (string, name) {
68 return rhinoContext.evaluateString(this, string, name, 0, null);
71 exists = function (fileName) {
72 return (new java.io.File(fileName)).exists();
75 //Define a console.log for easier logging. Don't
77 if (typeof console === 'undefined') {
80 print.apply(undefined, arguments);
84 } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
87 //Get the fs module via Node's require before it
88 //gets replaced. Used in require/node.js
91 path = require('path');
92 //In Node 0.7+ existsSync is on fs.
93 existsForNode = fs.existsSync || path.existsSync;
95 nodeRequire = require;
97 reqMain = require.main;
99 //Temporarily hide require and define to allow require.js to define
104 readFile = function (path) {
105 return fs.readFileSync(path, 'utf8');
108 exec = function (string, name) {
109 return vm.runInThisContext(this.requirejsVars.require.makeNodeWrapper(string),
110 name ? fs.realpathSync(name) : '');
113 exists = function (fileName) {
114 return existsForNode(fileName);
118 fileName = process.argv[2];
120 if (fileName && fileName.indexOf('-') === 0) {
121 commandOption = fileName.substring(1);
122 fileName = process.argv[3];
124 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) {
127 Components.utils['import']('resource://gre/modules/FileUtils.jsm');
128 Cc = Components.classes;
129 Ci = Components.interfaces;
133 if (fileName && fileName.indexOf('-') === 0) {
134 commandOption = fileName.substring(1);
139 isWindows: ('@mozilla.org/windows-registry-key;1' in Cc),
141 return FileUtils.getFile("CurWorkD", []).path;
144 //Remove . and .. from paths, normalize on front slashes
145 normalize: function (path) {
146 //There has to be an easier way to do this.
148 firstChar = path.charAt(0);
150 if (firstChar !== '/' &&
151 firstChar !== '\\' &&
152 path.indexOf(':') === -1) {
153 //A relative path. Use the current working directory.
154 path = xpcUtil.cwd() + '/' + path;
157 ary = path.replace(/\\/g, '/').split('/');
159 for (i = 0; i < ary.length; i += 1) {
164 } else if (part === '..') {
165 ary.splice(i - 1, 2);
169 return ary.join('/');
172 xpfile: function (path) {
175 fullPath = xpcUtil.normalize(path);
176 if (xpcUtil.isWindows) {
177 fullPath = fullPath.replace(/\//g, '\\');
179 return new FileUtils.File(fullPath);
181 throw new Error((fullPath || path) + ' failed: ' + e);
185 readFile: function (/*String*/path, /*String?*/encoding) {
186 //A file read function that can deal with BOMs
187 encoding = encoding || "utf-8";
189 var inStream, convertStream,
191 fileObj = xpcUtil.xpfile(path);
193 //XPCOM, you so crazy
195 inStream = Cc['@mozilla.org/network/file-input-stream;1']
196 .createInstance(Ci.nsIFileInputStream);
197 inStream.init(fileObj, 1, 0, false);
199 convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
200 .createInstance(Ci.nsIConverterInputStream);
201 convertStream.init(inStream, encoding, inStream.available(),
202 Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
204 convertStream.readString(inStream.available(), readData);
205 return readData.value;
207 throw new Error((fileObj && fileObj.path || '') + ': ' + e);
210 convertStream.close();
219 readFile = xpcUtil.readFile;
221 exec = function (string) {
225 exists = function (fileName) {
226 return xpcUtil.xpfile(fileName).exists();
229 //Define a console.log for easier logging. Don't
231 if (typeof console === 'undefined') {
234 print.apply(undefined, arguments);
240 /** vim: et:ts=4:sw=4:sts=4
241 * @license RequireJS 2.1.8 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
242 * Available via the MIT or new BSD license.
243 * see: http://github.com/jrburke/requirejs for details
245 //Not using strict: uneven strict support in browsers, #392, and causes
246 //problems with requirejs.exec()/transpiler plugins that may not be strict.
247 /*jslint regexp: true, nomen: true, sloppy: true */
248 /*global window, navigator, document, importScripts, setTimeout, opera */
252 var req, s, head, baseElement, dataMain, src,
253 interactiveScript, currentlyAddingScript, mainScript, subPath,
255 commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
256 cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
257 jsSuffixRegExp = /\.js$/,
258 currDirRegExp = /^\.\//,
259 op = Object.prototype,
260 ostring = op.toString,
261 hasOwn = op.hasOwnProperty,
262 ap = Array.prototype,
264 isBrowser = !!(typeof window !== 'undefined' && navigator && window.document),
265 isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
266 //PS3 indicates loaded and complete, but need to wait for complete
267 //specifically. Sequence is 'loading', 'loaded', execution,
268 // then 'complete'. The UA check is unfortunate, but not sure how
269 //to feature test w/o causing perf issues.
270 readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
271 /^complete$/ : /^(complete|loaded)$/,
272 defContextName = '_',
273 //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
274 isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
278 useInteractive = false;
280 function isFunction(it) {
281 return ostring.call(it) === '[object Function]';
284 function isArray(it) {
285 return ostring.call(it) === '[object Array]';
289 * Helper function for iterating over an array. If the func returns
290 * a true value, it will break out of the loop.
292 function each(ary, func) {
295 for (i = 0; i < ary.length; i += 1) {
296 if (ary[i] && func(ary[i], i, ary)) {
304 * Helper function for iterating over an array backwards. If the func
305 * returns a true value, it will break out of the loop.
307 function eachReverse(ary, func) {
310 for (i = ary.length - 1; i > -1; i -= 1) {
311 if (ary[i] && func(ary[i], i, ary)) {
318 function hasProp(obj, prop) {
319 return hasOwn.call(obj, prop);
322 function getOwn(obj, prop) {
323 return hasProp(obj, prop) && obj[prop];
327 * Cycles over properties in an object and calls a function for each
328 * property value. If the function returns a truthy value, then the
329 * iteration is stopped.
331 function eachProp(obj, func) {
334 if (hasProp(obj, prop)) {
335 if (func(obj[prop], prop)) {
343 * Simple function to mix in properties from source into target,
344 * but only if target does not already have a property of the same name.
346 function mixin(target, source, force, deepStringMixin) {
348 eachProp(source, function (value, prop) {
349 if (force || !hasProp(target, prop)) {
350 if (deepStringMixin && typeof value !== 'string') {
354 mixin(target[prop], value, force, deepStringMixin);
356 target[prop] = value;
364 //Similar to Function.prototype.bind, but the 'this' object is specified
365 //first, since it is easier to read/figure out what 'this' will be.
366 function bind(obj, fn) {
368 return fn.apply(obj, arguments);
373 return document.getElementsByTagName('script');
376 function defaultOnError(err) {
380 //Allow getting a global that expressed in
381 //dot notation, like 'a.b.c'.
382 function getGlobal(value) {
387 each(value.split('.'), function (part) {
394 * Constructs an error with a pointer to an URL with more information.
395 * @param {String} id the error ID that maps to an ID on a web page.
396 * @param {String} message human readable error.
397 * @param {Error} [err] the original error, if there is one.
401 function makeError(id, msg, err, requireModules) {
402 var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
404 e.requireModules = requireModules;
406 e.originalError = err;
411 if (typeof define !== 'undefined') {
412 //If a define is already in play via another AMD loader,
417 if (typeof requirejs !== 'undefined') {
418 if (isFunction(requirejs)) {
419 //Do not overwrite and existing requirejs instance.
423 requirejs = undefined;
426 //Allow for a require config object
427 if (typeof require !== 'undefined' && !isFunction(require)) {
428 //assume it is a config object.
433 function newContext(contextName) {
434 var inCheckLoaded, Module, context, handlers,
435 checkLoadedTimeoutId,
437 //Defaults. Do not set a default for map
438 //config to speed up normalize(), which
439 //will run faster if there is no default.
448 //registry of just enabled modules, to speed
449 //cycle breaking code when lots of modules
450 //are registered, but not activated.
451 enabledRegistry = {},
457 unnormalizedCounter = 1;
460 * Trims the . and .. from an array of path segments.
461 * It will keep a leading path segment if a .. will become
462 * the first path segment, to help with module name lookups,
463 * which act like paths, but can be remapped. But the end result,
464 * all paths that use this function should look normalized.
465 * NOTE: this method MODIFIES the input array.
466 * @param {Array} ary the array of path segments.
468 function trimDots(ary) {
470 for (i = 0; ary[i]; i += 1) {
475 } else if (part === '..') {
476 if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
477 //End of the line. Keep at least one non-dot
478 //path segment at the front so it can be mapped
479 //correctly to disk. Otherwise, there is likely
480 //no path mapping for a path starting with '..'.
481 //This can still fail, but catches the most reasonable
485 ary.splice(i - 1, 2);
493 * Given a relative module name, like ./something, normalize it to
494 * a real name that can be mapped to a path.
495 * @param {String} name the relative name
496 * @param {String} baseName a real name that the name arg is relative
498 * @param {Boolean} applyMap apply the map config to the value. Should
499 * only be done if this normalization is for a dependency ID.
500 * @returns {String} normalized name
502 function normalize(name, baseName, applyMap) {
503 var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
504 foundMap, foundI, foundStarMap, starI,
505 baseParts = baseName && baseName.split('/'),
506 normalizedBaseParts = baseParts,
508 starMap = map && map['*'];
510 //Adjust any relative paths.
511 if (name && name.charAt(0) === '.') {
512 //If have a base name, try to normalize against it,
513 //otherwise, assume it is a top-level require that will
514 //be relative to baseUrl in the end.
516 if (getOwn(config.pkgs, baseName)) {
517 //If the baseName is a package name, then just treat it as one
518 //name to concat the name with.
519 normalizedBaseParts = baseParts = [baseName];
521 //Convert baseName to array, and lop off the last part,
522 //so that . matches that 'directory' and not name of the baseName's
523 //module. For instance, baseName of 'one/two/three', maps to
524 //'one/two/three.js', but we want the directory, 'one/two' for
525 //this normalization.
526 normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
529 name = normalizedBaseParts.concat(name.split('/'));
532 //Some use of packages may use a . path to reference the
533 //'main' module name, so normalize for that.
534 pkgConfig = getOwn(config.pkgs, (pkgName = name[0]));
535 name = name.join('/');
536 if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
539 } else if (name.indexOf('./') === 0) {
540 // No baseName, so this is ID is resolved relative
541 // to baseUrl, pull off the leading dot.
542 name = name.substring(2);
546 //Apply map config if available.
547 if (applyMap && map && (baseParts || starMap)) {
548 nameParts = name.split('/');
550 for (i = nameParts.length; i > 0; i -= 1) {
551 nameSegment = nameParts.slice(0, i).join('/');
554 //Find the longest baseName segment match in the config.
555 //So, do joins on the biggest to smallest lengths of baseParts.
556 for (j = baseParts.length; j > 0; j -= 1) {
557 mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
559 //baseName segment has config, find if it has one for
562 mapValue = getOwn(mapValue, nameSegment);
564 //Match, update name to the new value.
577 //Check for a star map match, but just hold on to it,
578 //if there is a shorter segment match later in a matching
579 //config, then favor over this star map.
580 if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
581 foundStarMap = getOwn(starMap, nameSegment);
586 if (!foundMap && foundStarMap) {
587 foundMap = foundStarMap;
592 nameParts.splice(0, foundI, foundMap);
593 name = nameParts.join('/');
600 function removeScript(name) {
602 each(scripts(), function (scriptNode) {
603 if (scriptNode.getAttribute('data-requiremodule') === name &&
604 scriptNode.getAttribute('data-requirecontext') === context.contextName) {
605 scriptNode.parentNode.removeChild(scriptNode);
612 function hasPathFallback(id) {
613 var pathConfig = getOwn(config.paths, id);
614 if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
616 //Pop off the first array value, since it failed, and
619 context.require.undef(id);
620 context.require([id]);
625 //Turns a plugin!resource to [plugin, resource]
626 //with the plugin being undefined if the name
627 //did not have a plugin prefix.
628 function splitPrefix(name) {
630 index = name ? name.indexOf('!') : -1;
632 prefix = name.substring(0, index);
633 name = name.substring(index + 1, name.length);
635 return [prefix, name];
639 * Creates a module mapping that includes plugin prefix, module
640 * name, and path. If parentModuleMap is provided it will
641 * also normalize the name via require.normalize()
643 * @param {String} name the module name
644 * @param {String} [parentModuleMap] parent module map
645 * for the module name, used to resolve relative names.
646 * @param {Boolean} isNormalized: is the ID already normalized.
647 * This is true if this call is done for a define() module ID.
648 * @param {Boolean} applyMap: apply the map config to the ID.
649 * Should only be true if this map is for a dependency.
653 function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
654 var url, pluginModule, suffix, nameParts,
656 parentName = parentModuleMap ? parentModuleMap.name : null,
661 //If no name, then it means it is a require call, generate an
665 name = '_@r' + (requireCounter += 1);
668 nameParts = splitPrefix(name);
669 prefix = nameParts[0];
673 prefix = normalize(prefix, parentName, applyMap);
674 pluginModule = getOwn(defined, prefix);
677 //Account for relative paths if there is a base name.
680 if (pluginModule && pluginModule.normalize) {
681 //Plugin is loaded, use its normalize method.
682 normalizedName = pluginModule.normalize(name, function (name) {
683 return normalize(name, parentName, applyMap);
686 normalizedName = normalize(name, parentName, applyMap);
690 normalizedName = normalize(name, parentName, applyMap);
692 //Normalized name may be a plugin ID due to map config
693 //application in normalize. The map config values must
694 //already be normalized, so do not need to redo that part.
695 nameParts = splitPrefix(normalizedName);
696 prefix = nameParts[0];
697 normalizedName = nameParts[1];
700 url = context.nameToUrl(normalizedName);
704 //If the id is a plugin id that cannot be determined if it needs
705 //normalization, stamp it with a unique ID so two matching relative
706 //ids that may conflict can be separate.
707 suffix = prefix && !pluginModule && !isNormalized ?
708 '_unnormalized' + (unnormalizedCounter += 1) :
713 name: normalizedName,
714 parentMap: parentModuleMap,
715 unnormalized: !!suffix,
717 originalName: originalName,
720 prefix + '!' + normalizedName :
721 normalizedName) + suffix
725 function getModule(depMap) {
727 mod = getOwn(registry, id);
730 mod = registry[id] = new context.Module(depMap);
736 function on(depMap, name, fn) {
738 mod = getOwn(registry, id);
740 if (hasProp(defined, id) &&
741 (!mod || mod.defineEmitComplete)) {
742 if (name === 'defined') {
746 mod = getModule(depMap);
747 if (mod.error && name === 'error') {
755 function onError(err, errback) {
756 var ids = err.requireModules,
762 each(ids, function (id) {
763 var mod = getOwn(registry, id);
765 //Set error on module, so it skips timeout checks.
767 if (mod.events.error) {
769 mod.emit('error', err);
781 * Internal method to transfer globalQueue items to this context's
784 function takeGlobalQueue() {
785 //Push all the globalDefQueue items into the context's defQueue
786 if (globalDefQueue.length) {
787 //Array splice in the values since the context code has a
788 //local var ref to defQueue, so cannot just reassign the one
791 [defQueue.length - 1, 0].concat(globalDefQueue));
797 'require': function (mod) {
801 return (mod.require = context.makeRequire(mod.map));
804 'exports': function (mod) {
805 mod.usingExports = true;
806 if (mod.map.isDefine) {
810 return (mod.exports = defined[mod.map.id] = {});
814 'module': function (mod) {
818 return (mod.module = {
821 config: function () {
823 pkg = getOwn(config.pkgs, mod.map.id);
824 // For packages, only support config targeted
825 // at the main module.
826 c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) :
827 getOwn(config.config, mod.map.id);
830 exports: defined[mod.map.id]
836 function cleanRegistry(id) {
837 //Clean up machinery used for waiting modules.
839 delete enabledRegistry[id];
842 function breakCycle(mod, traced, processed) {
846 mod.emit('error', mod.error);
849 each(mod.depMaps, function (depMap, i) {
850 var depId = depMap.id,
851 dep = getOwn(registry, depId);
853 //Only force things that have not completed
854 //being defined, so still in the registry,
855 //and only if it has not been matched up
856 //in the module already.
857 if (dep && !mod.depMatched[i] && !processed[depId]) {
858 if (getOwn(traced, depId)) {
859 mod.defineDep(i, defined[depId]);
860 mod.check(); //pass false?
862 breakCycle(dep, traced, processed);
866 processed[id] = true;
870 function checkLoaded() {
871 var map, modId, err, usingPathFallback,
872 waitInterval = config.waitSeconds * 1000,
873 //It is possible to disable the wait interval by using waitSeconds of 0.
874 expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
877 stillLoading = false,
878 needCycleCheck = true;
880 //Do not bother if this call was a result of a cycle break.
885 inCheckLoaded = true;
887 //Figure out the state of all the modules.
888 eachProp(enabledRegistry, function (mod) {
892 //Skip things that are not enabled or in error state.
902 //If the module should be executed, and it has not
903 //been inited and time is up, remember it.
904 if (!mod.inited && expired) {
905 if (hasPathFallback(modId)) {
906 usingPathFallback = true;
912 } else if (!mod.inited && mod.fetched && map.isDefine) {
915 //No reason to keep looking for unfinished
916 //loading. If the only stillLoading is a
917 //plugin resource though, keep going,
918 //because it may be that a plugin resource
919 //is waiting on a non-plugin cycle.
920 return (needCycleCheck = false);
926 if (expired && noLoads.length) {
927 //If wait time expired, throw error of unloaded modules.
928 err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
929 err.contextName = context.contextName;
933 //Not expired, check for a cycle.
934 if (needCycleCheck) {
935 each(reqCalls, function (mod) {
936 breakCycle(mod, {}, {});
940 //If still waiting on loads, and the waiting load is something
941 //other than a plugin resource, or there are still outstanding
942 //scripts, then just try back later.
943 if ((!expired || usingPathFallback) && stillLoading) {
944 //Something is still waiting to load. Wait for it, but only
945 //if a timeout is not already in effect.
946 if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
947 checkLoadedTimeoutId = setTimeout(function () {
948 checkLoadedTimeoutId = 0;
954 inCheckLoaded = false;
957 Module = function (map) {
958 this.events = getOwn(undefEvents, map.id) || {};
960 this.shim = getOwn(config.shim, map.id);
961 this.depExports = [];
963 this.depMatched = [];
964 this.pluginMaps = {};
967 /* this.exports this.factory
969 this.enabled, this.fetched
974 init: function (depMaps, factory, errback, options) {
975 options = options || {};
977 //Do not do more inits if already done. Can happen if there
978 //are multiple define calls for the same module. That is not
979 //a normal, common case, but it is also not unexpected.
984 this.factory = factory;
987 //Register for errors on this module.
988 this.on('error', errback);
989 } else if (this.events.error) {
990 //If no errback already, but there are error listeners
991 //on this module, set up an errback to pass to the deps.
992 errback = bind(this, function (err) {
993 this.emit('error', err);
997 //Do a copy of the dependency array, so that
998 //source inputs are not modified. For example
999 //"shim" deps are passed in here directly, and
1000 //doing a direct modification of the depMaps array
1001 //would affect that config.
1002 this.depMaps = depMaps && depMaps.slice(0);
1004 this.errback = errback;
1006 //Indicate this module has be initialized
1009 this.ignore = options.ignore;
1011 //Could have option to init this module in enabled mode,
1012 //or could have been previously marked as enabled. However,
1013 //the dependencies are not known until init is called. So
1014 //if enabled previously, now trigger dependencies as enabled.
1015 if (options.enabled || this.enabled) {
1016 //Enable this module and dependencies.
1017 //Will call this.check()
1024 defineDep: function (i, depExports) {
1025 //Because of cycles, defined callback for a given
1026 //export can be called more than once.
1027 if (!this.depMatched[i]) {
1028 this.depMatched[i] = true;
1030 this.depExports[i] = depExports;
1034 fetch: function () {
1038 this.fetched = true;
1040 context.startTime = (new Date()).getTime();
1044 //If the manager is for a plugin managed resource,
1045 //ask the plugin to load it now.
1047 context.makeRequire(this.map, {
1048 enableBuildCallback: true
1049 })(this.shim.deps || [], bind(this, function () {
1050 return map.prefix ? this.callPlugin() : this.load();
1053 //Regular dependency.
1054 return map.prefix ? this.callPlugin() : this.load();
1059 var url = this.map.url;
1061 //Regular dependency.
1062 if (!urlFetched[url]) {
1063 urlFetched[url] = true;
1064 context.load(this.map.id, url);
1069 * Checks if the module is ready to define itself, and if so,
1072 check: function () {
1073 if (!this.enabled || this.enabling) {
1079 depExports = this.depExports,
1080 exports = this.exports,
1081 factory = this.factory;
1085 } else if (this.error) {
1086 this.emit('error', this.error);
1087 } else if (!this.defining) {
1088 //The factory could trigger another require call
1089 //that would result in checking this module to
1090 //define itself again. If already in the process
1091 //of doing that, skip this work.
1092 this.defining = true;
1094 if (this.depCount < 1 && !this.defined) {
1095 if (isFunction(factory)) {
1096 //If there is an error listener, favor passing
1097 //to that instead of throwing an error. However,
1098 //only do it for define()'d modules. require
1099 //errbacks should not be called for failures in
1100 //their callbacks (#699). However if a global
1101 //onError is set, use that.
1102 if ((this.events.error && this.map.isDefine) ||
1103 req.onError !== defaultOnError) {
1105 exports = context.execCb(id, factory, depExports, exports);
1110 exports = context.execCb(id, factory, depExports, exports);
1113 if (this.map.isDefine) {
1114 //If setting exports via 'module' is in play,
1115 //favor that over return value and exports. After that,
1116 //favor a non-undefined return value over exports use.
1117 cjsModule = this.module;
1119 cjsModule.exports !== undefined &&
1120 //Make sure it is not already the exports value
1121 cjsModule.exports !== this.exports) {
1122 exports = cjsModule.exports;
1123 } else if (exports === undefined && this.usingExports) {
1124 //exports already set the defined value.
1125 exports = this.exports;
1130 err.requireMap = this.map;
1131 err.requireModules = this.map.isDefine ? [this.map.id] : null;
1132 err.requireType = this.map.isDefine ? 'define' : 'require';
1133 return onError((this.error = err));
1137 //Just a literal value
1141 this.exports = exports;
1143 if (this.map.isDefine && !this.ignore) {
1144 defined[id] = exports;
1146 if (req.onResourceLoad) {
1147 req.onResourceLoad(context, this.map, this.depMaps);
1154 this.defined = true;
1157 //Finished the define stage. Allow calling check again
1158 //to allow define notifications below in the case of a
1160 this.defining = false;
1162 if (this.defined && !this.defineEmitted) {
1163 this.defineEmitted = true;
1164 this.emit('defined', this.exports);
1165 this.defineEmitComplete = true;
1171 callPlugin: function () {
1174 //Map already normalized the prefix.
1175 pluginMap = makeModuleMap(map.prefix);
1177 //Mark this as a dependency for this plugin, so it
1178 //can be traced for cycles.
1179 this.depMaps.push(pluginMap);
1181 on(pluginMap, 'defined', bind(this, function (plugin) {
1182 var load, normalizedMap, normalizedMod,
1183 name = this.map.name,
1184 parentName = this.map.parentMap ? this.map.parentMap.name : null,
1185 localRequire = context.makeRequire(map.parentMap, {
1186 enableBuildCallback: true
1189 //If current map is not normalized, wait for that
1190 //normalized name to load instead of continuing.
1191 if (this.map.unnormalized) {
1192 //Normalize the ID if the plugin allows it.
1193 if (plugin.normalize) {
1194 name = plugin.normalize(name, function (name) {
1195 return normalize(name, parentName, true);
1199 //prefix and name should already be normalized, no need
1200 //for applying map config again either.
1201 normalizedMap = makeModuleMap(map.prefix + '!' + name,
1202 this.map.parentMap);
1204 'defined', bind(this, function (value) {
1205 this.init([], function () { return value; }, null, {
1211 normalizedMod = getOwn(registry, normalizedMap.id);
1212 if (normalizedMod) {
1213 //Mark this as a dependency for this plugin, so it
1214 //can be traced for cycles.
1215 this.depMaps.push(normalizedMap);
1217 if (this.events.error) {
1218 normalizedMod.on('error', bind(this, function (err) {
1219 this.emit('error', err);
1222 normalizedMod.enable();
1228 load = bind(this, function (value) {
1229 this.init([], function () { return value; }, null, {
1234 load.error = bind(this, function (err) {
1237 err.requireModules = [id];
1239 //Remove temp unnormalized modules for this module,
1240 //since they will never be resolved otherwise now.
1241 eachProp(registry, function (mod) {
1242 if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
1243 cleanRegistry(mod.map.id);
1250 //Allow plugins to load other code without having to know the
1251 //context or how to 'complete' the load.
1252 load.fromText = bind(this, function (text, textAlt) {
1253 /*jslint evil: true */
1254 var moduleName = map.name,
1255 moduleMap = makeModuleMap(moduleName),
1256 hasInteractive = useInteractive;
1258 //As of 2.1.0, support just passing the text, to reinforce
1259 //fromText only being called once per resource. Still
1260 //support old style of passing moduleName but discard
1261 //that moduleName in favor of the internal ref.
1266 //Turn off interactive script matching for IE for any define
1267 //calls in the text, then turn it back on at the end.
1268 if (hasInteractive) {
1269 useInteractive = false;
1272 //Prime the system by creating a module instance for
1274 getModule(moduleMap);
1276 //Transfer any config to this other module.
1277 if (hasProp(config.config, id)) {
1278 config.config[moduleName] = config.config[id];
1284 return onError(makeError('fromtexteval',
1285 'fromText eval for ' + id +
1291 if (hasInteractive) {
1292 useInteractive = true;
1295 //Mark this as a dependency for the plugin
1297 this.depMaps.push(moduleMap);
1299 //Support anonymous modules.
1300 context.completeLoad(moduleName);
1302 //Bind the value of that module to the value for this
1304 localRequire([moduleName], load);
1307 //Use parentName here since the plugin's name is not reliable,
1308 //could be some weird string with no path that actually wants to
1309 //reference the parentName's path.
1310 plugin.load(map.name, localRequire, load, config);
1313 context.enable(pluginMap, this);
1314 this.pluginMaps[pluginMap.id] = pluginMap;
1317 enable: function () {
1318 enabledRegistry[this.map.id] = this;
1319 this.enabled = true;
1321 //Set flag mentioning that the module is enabling,
1322 //so that immediate calls to the defined callbacks
1323 //for dependencies do not trigger inadvertent load
1324 //with the depCount still being zero.
1325 this.enabling = true;
1327 //Enable each dependency
1328 each(this.depMaps, bind(this, function (depMap, i) {
1329 var id, mod, handler;
1331 if (typeof depMap === 'string') {
1332 //Dependency needs to be converted to a depMap
1333 //and wired up to this module.
1334 depMap = makeModuleMap(depMap,
1335 (this.map.isDefine ? this.map : this.map.parentMap),
1338 this.depMaps[i] = depMap;
1340 handler = getOwn(handlers, depMap.id);
1343 this.depExports[i] = handler(this);
1349 on(depMap, 'defined', bind(this, function (depExports) {
1350 this.defineDep(i, depExports);
1355 on(depMap, 'error', bind(this, this.errback));
1362 //Skip special modules like 'require', 'exports', 'module'
1363 //Also, don't call enable if it is already enabled,
1364 //important in circular dependency cases.
1365 if (!hasProp(handlers, id) && mod && !mod.enabled) {
1366 context.enable(depMap, this);
1370 //Enable each plugin that is used in
1372 eachProp(this.pluginMaps, bind(this, function (pluginMap) {
1373 var mod = getOwn(registry, pluginMap.id);
1374 if (mod && !mod.enabled) {
1375 context.enable(pluginMap, this);
1379 this.enabling = false;
1384 on: function (name, cb) {
1385 var cbs = this.events[name];
1387 cbs = this.events[name] = [];
1392 emit: function (name, evt) {
1393 each(this.events[name], function (cb) {
1396 if (name === 'error') {
1397 //Now that the error handler was triggered, remove
1398 //the listeners, since this broken Module instance
1399 //can stay around for a while in the registry.
1400 delete this.events[name];
1405 function callGetModule(args) {
1406 //Skip modules already defined.
1407 if (!hasProp(defined, args[0])) {
1408 getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
1412 function removeListener(node, func, name, ieName) {
1413 //Favor detachEvent because of IE9
1414 //issue, see attachEvent/addEventListener comment elsewhere
1416 if (node.detachEvent && !isOpera) {
1417 //Probably IE. If not it will throw an error, which will be
1420 node.detachEvent(ieName, func);
1423 node.removeEventListener(name, func, false);
1428 * Given an event from a script node, get the requirejs info from it,
1429 * and then removes the event listeners on the node.
1430 * @param {Event} evt
1433 function getScriptData(evt) {
1434 //Using currentTarget instead of target for Firefox 2.0's sake. Not
1435 //all old browsers will be supported, but this one was easy enough
1436 //to support and still makes sense.
1437 var node = evt.currentTarget || evt.srcElement;
1439 //Remove the listeners once here.
1440 removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
1441 removeListener(node, context.onScriptError, 'error');
1445 id: node && node.getAttribute('data-requiremodule')
1449 function intakeDefines() {
1452 //Any defined modules in the global queue, intake them now.
1455 //Make sure any remaining defQueue items get properly processed.
1456 while (defQueue.length) {
1457 args = defQueue.shift();
1458 if (args[0] === null) {
1459 return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
1461 //args are id, deps, factory. Should be normalized by the
1462 //define() function.
1463 callGetModule(args);
1470 contextName: contextName,
1473 urlFetched: urlFetched,
1476 makeModuleMap: makeModuleMap,
1477 nextTick: req.nextTick,
1481 * Set a configuration for the context.
1482 * @param {Object} cfg config object to integrate.
1484 configure: function (cfg) {
1485 //Make sure the baseUrl ends in a slash.
1487 if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
1492 //Save off the paths and packages since they require special processing,
1493 //they are additive.
1494 var pkgs = config.pkgs,
1502 eachProp(cfg, function (value, prop) {
1504 if (prop === 'map') {
1508 mixin(config[prop], value, true, true);
1510 mixin(config[prop], value, true);
1513 config[prop] = value;
1519 eachProp(cfg.shim, function (value, id) {
1520 //Normalize the structure
1521 if (isArray(value)) {
1526 if ((value.exports || value.init) && !value.exportsFn) {
1527 value.exportsFn = context.makeShimExports(value);
1534 //Adjust packages if necessary.
1536 each(cfg.packages, function (pkgObj) {
1539 pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
1540 location = pkgObj.location;
1542 //Create a brand new object on pkgs, since currentPackages can
1543 //be passed in again, and config.pkgs is the internal transformed
1544 //state for all package configs.
1545 pkgs[pkgObj.name] = {
1547 location: location || pkgObj.name,
1548 //Remove leading dot in main, so main paths are normalized,
1549 //and remove any trailing .js, since different package
1550 //envs have different conventions: some use a module name,
1551 //some use a file name.
1552 main: (pkgObj.main || 'main')
1553 .replace(currDirRegExp, '')
1554 .replace(jsSuffixRegExp, '')
1558 //Done with modifications, assing packages back to context config
1562 //If there are any "waiting to execute" modules in the registry,
1563 //update the maps for them, since their info, like URLs to load,
1565 eachProp(registry, function (mod, id) {
1566 //If module already has init called, since it is too
1567 //late to modify them, and ignore unnormalized ones
1568 //since they are transient.
1569 if (!mod.inited && !mod.map.unnormalized) {
1570 mod.map = makeModuleMap(id);
1574 //If a deps array or a config callback is specified, then call
1575 //require with those args. This is useful when require is defined as a
1576 //config object before require.js is loaded.
1577 if (cfg.deps || cfg.callback) {
1578 context.require(cfg.deps || [], cfg.callback);
1582 makeShimExports: function (value) {
1586 ret = value.init.apply(global, arguments);
1588 return ret || (value.exports && getGlobal(value.exports));
1593 makeRequire: function (relMap, options) {
1594 options = options || {};
1596 function localRequire(deps, callback, errback) {
1597 var id, map, requireMod;
1599 if (options.enableBuildCallback && callback && isFunction(callback)) {
1600 callback.__requireJsBuild = true;
1603 if (typeof deps === 'string') {
1604 if (isFunction(callback)) {
1606 return onError(makeError('requireargs', 'Invalid require call'), errback);
1609 //If require|exports|module are requested, get the
1610 //value for them from the special handlers. Caveat:
1611 //this only works while module is being defined.
1612 if (relMap && hasProp(handlers, deps)) {
1613 return handlers[deps](registry[relMap.id]);
1616 //Synchronous access to one module. If require.get is
1617 //available (as in the Node adapter), prefer that.
1619 return req.get(context, deps, relMap, localRequire);
1622 //Normalize module name, if it contains . or ..
1623 map = makeModuleMap(deps, relMap, false, true);
1626 if (!hasProp(defined, id)) {
1627 return onError(makeError('notloaded', 'Module name "' +
1629 '" has not been loaded yet for context: ' +
1631 (relMap ? '' : '. Use require([])')));
1636 //Grab defines waiting in the global queue.
1639 //Mark all the dependencies as needing to be loaded.
1640 context.nextTick(function () {
1641 //Some defines could have been added since the
1642 //require call, collect them.
1645 requireMod = getModule(makeModuleMap(null, relMap));
1647 //Store if map config should be applied to this require
1648 //call for dependencies.
1649 requireMod.skipMap = options.skipMap;
1651 requireMod.init(deps, callback, errback, {
1658 return localRequire;
1661 mixin(localRequire, {
1662 isBrowser: isBrowser,
1665 * Converts a module name + .extension into an URL path.
1666 * *Requires* the use of a module name. It does not support using
1667 * plain URLs like nameToUrl.
1669 toUrl: function (moduleNamePlusExt) {
1671 index = moduleNamePlusExt.lastIndexOf('.'),
1672 segment = moduleNamePlusExt.split('/')[0],
1673 isRelative = segment === '.' || segment === '..';
1675 //Have a file extension alias, and it is not the
1676 //dots from a relative path.
1677 if (index !== -1 && (!isRelative || index > 1)) {
1678 ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
1679 moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
1682 return context.nameToUrl(normalize(moduleNamePlusExt,
1683 relMap && relMap.id, true), ext, true);
1686 defined: function (id) {
1687 return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
1690 specified: function (id) {
1691 id = makeModuleMap(id, relMap, false, true).id;
1692 return hasProp(defined, id) || hasProp(registry, id);
1696 //Only allow undef on top level require calls
1698 localRequire.undef = function (id) {
1699 //Bind any waiting define() calls to this context,
1703 var map = makeModuleMap(id, relMap, true),
1704 mod = getOwn(registry, id);
1707 delete urlFetched[map.url];
1708 delete undefEvents[id];
1711 //Hold on to listeners in case the
1712 //module will be attempted to be reloaded
1713 //using a different config.
1714 if (mod.events.defined) {
1715 undefEvents[id] = mod.events;
1723 return localRequire;
1727 * Called to enable a module if it is still in the registry
1728 * awaiting enablement. A second arg, parent, the parent module,
1729 * is passed in for context, when this method is overriden by
1730 * the optimizer. Not shown here to keep code compact.
1732 enable: function (depMap) {
1733 var mod = getOwn(registry, depMap.id);
1735 getModule(depMap).enable();
1740 * Internal method used by environment adapters to complete a load event.
1741 * A load event could be a script load or just a load pass from a synchronous
1743 * @param {String} moduleName the name of the module to potentially complete.
1745 completeLoad: function (moduleName) {
1746 var found, args, mod,
1747 shim = getOwn(config.shim, moduleName) || {},
1748 shExports = shim.exports;
1752 while (defQueue.length) {
1753 args = defQueue.shift();
1754 if (args[0] === null) {
1755 args[0] = moduleName;
1756 //If already found an anonymous module and bound it
1757 //to this name, then this is some other anon module
1758 //waiting for its completeLoad to fire.
1763 } else if (args[0] === moduleName) {
1764 //Found matching define call for this script!
1768 callGetModule(args);
1771 //Do this after the cycle of callGetModule in case the result
1772 //of those calls/init calls changes the registry.
1773 mod = getOwn(registry, moduleName);
1775 if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
1776 if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
1777 if (hasPathFallback(moduleName)) {
1780 return onError(makeError('nodefine',
1781 'No define call for ' + moduleName,
1786 //A script that does not call define(), so just simulate
1788 callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
1796 * Converts a module name to a file path. Supports cases where
1797 * moduleName may actually be just an URL.
1798 * Note that it **does not** call normalize on the moduleName,
1799 * it is assumed to have already been normalized. This is an
1800 * internal API, not a public one. Use toUrl for the public API.
1802 nameToUrl: function (moduleName, ext, skipExt) {
1803 var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
1806 //If a colon is in the URL, it indicates a protocol is used and it is just
1807 //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
1808 //or ends with .js, then assume the user meant to use an url and not a module id.
1809 //The slash is important for protocol-less URLs as well as full paths.
1810 if (req.jsExtRegExp.test(moduleName)) {
1811 //Just a plain path, not module name lookup, so just return it.
1812 //Add extension if it is included. This is a bit wonky, only non-.js things pass
1813 //an extension, this method probably needs to be reworked.
1814 url = moduleName + (ext || '');
1816 //A module that needs to be converted to a path.
1817 paths = config.paths;
1820 syms = moduleName.split('/');
1821 //For each module name segment, see if there is a path
1822 //registered for it. Start with most specific name
1823 //and work up from it.
1824 for (i = syms.length; i > 0; i -= 1) {
1825 parentModule = syms.slice(0, i).join('/');
1826 pkg = getOwn(pkgs, parentModule);
1827 parentPath = getOwn(paths, parentModule);
1829 //If an array, it means there are a few choices,
1830 //Choose the one that is desired
1831 if (isArray(parentPath)) {
1832 parentPath = parentPath[0];
1834 syms.splice(0, i, parentPath);
1837 //If module name is just the package name, then looking
1838 //for the main module.
1839 if (moduleName === pkg.name) {
1840 pkgPath = pkg.location + '/' + pkg.main;
1842 pkgPath = pkg.location;
1844 syms.splice(0, i, pkgPath);
1849 //Join the path parts together, then figure out if baseUrl is needed.
1850 url = syms.join('/');
1851 url += (ext || (/\?/.test(url) || skipExt ? '' : '.js'));
1852 url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
1855 return config.urlArgs ? url +
1856 ((url.indexOf('?') === -1 ? '?' : '&') +
1857 config.urlArgs) : url;
1860 //Delegates to req.load. Broken out as a separate function to
1861 //allow overriding in the optimizer.
1862 load: function (id, url) {
1863 req.load(context, id, url);
1867 * Executes a module callback function. Broken out as a separate function
1868 * solely to allow the build system to sequence the files in the built
1869 * layer in the right sequence.
1873 execCb: function (name, callback, args, exports) {
1874 return callback.apply(exports, args);
1878 * callback for script loads, used to check status of loading.
1880 * @param {Event} evt the event from the browser for the script
1883 onScriptLoad: function (evt) {
1884 //Using currentTarget instead of target for Firefox 2.0's sake. Not
1885 //all old browsers will be supported, but this one was easy enough
1886 //to support and still makes sense.
1887 if (evt.type === 'load' ||
1888 (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
1889 //Reset interactive script so a script node is not held onto for
1891 interactiveScript = null;
1893 //Pull out the name of the module and the context.
1894 var data = getScriptData(evt);
1895 context.completeLoad(data.id);
1900 * Callback for script errors.
1902 onScriptError: function (evt) {
1903 var data = getScriptData(evt);
1904 if (!hasPathFallback(data.id)) {
1905 return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id]));
1910 context.require = context.makeRequire();
1917 * If the only argument to require is a string, then the module that
1918 * is represented by that string is fetched for the appropriate context.
1920 * If the first argument is an array, then it will be treated as an array
1921 * of dependency string names to fetch. An optional function callback can
1922 * be specified to execute when all of those dependencies are available.
1924 * Make a local req variable to help Caja compliance (it assumes things
1925 * on a require that are not standardized), and to give a short
1926 * name for minification/local scope use.
1928 req = requirejs = function (deps, callback, errback, optional) {
1930 //Find the right context, use default
1931 var context, config,
1932 contextName = defContextName;
1934 // Determine if have config object in the call.
1935 if (!isArray(deps) && typeof deps !== 'string') {
1936 // deps is a config object
1938 if (isArray(callback)) {
1939 // Adjust args if there are dependencies
1948 if (config && config.context) {
1949 contextName = config.context;
1952 context = getOwn(contexts, contextName);
1954 context = contexts[contextName] = req.s.newContext(contextName);
1958 context.configure(config);
1961 return context.require(deps, callback, errback);
1965 * Support require.config() to make it easier to cooperate with other
1966 * AMD loaders on globally agreed names.
1968 req.config = function (config) {
1973 * Execute something after the current tick
1974 * of the event loop. Override for other envs
1975 * that have a better solution than setTimeout.
1976 * @param {Function} fn function to execute later.
1978 req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
1980 } : function (fn) { fn(); };
1983 * Export require as a global, but only if it does not already exist.
1989 req.version = version;
1991 //Used to filter out dependencies that are already paths.
1992 req.jsExtRegExp = /^\/|:|\?|\.js$/;
1993 req.isBrowser = isBrowser;
1996 newContext: newContext
1999 //Create default context.
2002 //Exports some context-sensitive methods on global require.
2008 ], function (prop) {
2009 //Reference from contexts instead of early binding to default context,
2010 //so that during builds, the latest instance of the default context
2011 //with its config gets used.
2012 req[prop] = function () {
2013 var ctx = contexts[defContextName];
2014 return ctx.require[prop].apply(ctx, arguments);
2019 head = s.head = document.getElementsByTagName('head')[0];
2020 //If BASE tag is in play, using appendChild is a problem for IE6.
2021 //When that browser dies, this can be removed. Details in this jQuery bug:
2022 //http://dev.jquery.com/ticket/2709
2023 baseElement = document.getElementsByTagName('base')[0];
2025 head = s.head = baseElement.parentNode;
2030 * Any errors that require explicitly generates will be passed to this
2031 * function. Intercept/override it if you want custom error handling.
2032 * @param {Error} err the error object.
2034 req.onError = defaultOnError;
2037 * Creates the node for the load command. Only used in browser envs.
2039 req.createNode = function (config, moduleName, url) {
2040 var node = config.xhtml ?
2041 document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
2042 document.createElement('script');
2043 node.type = config.scriptType || 'text/javascript';
2044 node.charset = 'utf-8';
2050 * Does the request to load a module for the browser case.
2051 * Make this a separate function to allow other environments
2054 * @param {Object} context the require context to find state.
2055 * @param {String} moduleName the name of the module.
2056 * @param {Object} url the URL to the module.
2058 req.load = function (context, moduleName, url) {
2059 var config = (context && context.config) || {},
2062 //In the browser so use a script tag
2063 node = req.createNode(config, moduleName, url);
2065 node.setAttribute('data-requirecontext', context.contextName);
2066 node.setAttribute('data-requiremodule', moduleName);
2068 //Set up load listener. Test attachEvent first because IE9 has
2069 //a subtle issue in its addEventListener and script onload firings
2070 //that do not match the behavior of all other browsers with
2071 //addEventListener support, which fire the onload event for a
2072 //script right after the script execution. See:
2073 //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
2074 //UNFORTUNATELY Opera implements attachEvent but does not follow the script
2075 //script execution mode.
2076 if (node.attachEvent &&
2077 //Check if node.attachEvent is artificially added by custom script or
2078 //natively supported by browser
2079 //read https://github.com/jrburke/requirejs/issues/187
2080 //if we can NOT find [native code] then it must NOT natively supported.
2081 //in IE8, node.attachEvent does not have toString()
2082 //Note the test for "[native code" with no closing brace, see:
2083 //https://github.com/jrburke/requirejs/issues/273
2084 !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
2086 //Probably IE. IE (at least 6-8) do not fire
2087 //script onload right after executing the script, so
2088 //we cannot tie the anonymous define call to a name.
2089 //However, IE reports the script as being in 'interactive'
2090 //readyState at the time of the define call.
2091 useInteractive = true;
2093 node.attachEvent('onreadystatechange', context.onScriptLoad);
2094 //It would be great to add an error handler here to catch
2095 //404s in IE9+. However, onreadystatechange will fire before
2096 //the error handler, so that does not help. If addEventListener
2097 //is used, then IE will fire error before load, but we cannot
2098 //use that pathway given the connect.microsoft.com issue
2099 //mentioned above about not doing the 'script execute,
2100 //then fire the script load event listener before execute
2101 //next script' that other browsers do.
2102 //Best hope: IE10 fixes the issues,
2103 //and then destroys all installs of IE 6-9.
2104 //node.attachEvent('onerror', context.onScriptError);
2106 node.addEventListener('load', context.onScriptLoad, false);
2107 node.addEventListener('error', context.onScriptError, false);
2111 //For some cache cases in IE 6-8, the script executes before the end
2112 //of the appendChild execution, so to tie an anonymous define
2113 //call to the module name (which is stored on the node), hold on
2114 //to a reference to this node, but clear after the DOM insertion.
2115 currentlyAddingScript = node;
2117 head.insertBefore(node, baseElement);
2119 head.appendChild(node);
2121 currentlyAddingScript = null;
2124 } else if (isWebWorker) {
2126 //In a web worker, use importScripts. This is not a very
2127 //efficient use of importScripts, importScripts will block until
2128 //its script is downloaded and evaluated. However, if web workers
2129 //are in play, the expectation that a build has been done so that
2130 //only one script needs to be loaded anyway. This may need to be
2131 //reevaluated if other use cases become common.
2134 //Account for anonymous modules
2135 context.completeLoad(moduleName);
2137 context.onError(makeError('importscripts',
2138 'importScripts failed for ' +
2139 moduleName + ' at ' + url,
2146 function getInteractiveScript() {
2147 if (interactiveScript && interactiveScript.readyState === 'interactive') {
2148 return interactiveScript;
2151 eachReverse(scripts(), function (script) {
2152 if (script.readyState === 'interactive') {
2153 return (interactiveScript = script);
2156 return interactiveScript;
2159 //Look for a data-main script attribute, which could also adjust the baseUrl.
2161 //Figure out baseUrl. Get it from the script tag with require.js in it.
2162 eachReverse(scripts(), function (script) {
2163 //Set the 'head' where we can append children by
2164 //using the script's parent.
2166 head = script.parentNode;
2169 //Look for a data-main attribute to set main script for the page
2170 //to load. If it is there, the path to data main becomes the
2171 //baseUrl, if it is not already set.
2172 dataMain = script.getAttribute('data-main');
2174 //Preserve dataMain in case it is a path (i.e. contains '?')
2175 mainScript = dataMain;
2177 //Set final baseUrl if there is not already an explicit one.
2179 //Pull off the directory of data-main for use as the
2181 src = mainScript.split('/');
2182 mainScript = src.pop();
2183 subPath = src.length ? src.join('/') + '/' : './';
2185 cfg.baseUrl = subPath;
2188 //Strip off any trailing .js since mainScript is now
2189 //like a module name.
2190 mainScript = mainScript.replace(jsSuffixRegExp, '');
2192 //If mainScript is still a path, fall back to dataMain
2193 if (req.jsExtRegExp.test(mainScript)) {
2194 mainScript = dataMain;
2197 //Put the data-main script in the files to load.
2198 cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
2206 * The function that handles definitions of modules. Differs from
2207 * require() in that a string for the module should be the first argument,
2208 * and the function to execute after dependencies are loaded should
2209 * return a value to define the module corresponding to the first argument's
2212 define = function (name, deps, callback) {
2215 //Allow for anonymous modules
2216 if (typeof name !== 'string') {
2217 //Adjust args appropriately
2223 //This module may not have dependencies
2224 if (!isArray(deps)) {
2229 //If no name, and callback is a function, then figure out if it a
2230 //CommonJS thing with dependencies.
2231 if (!deps && isFunction(callback)) {
2233 //Remove comments from the callback string,
2234 //look for require calls, and pull them into the dependencies,
2235 //but only if there are function args.
2236 if (callback.length) {
2239 .replace(commentRegExp, '')
2240 .replace(cjsRequireRegExp, function (match, dep) {
2244 //May be a CommonJS thing even without require calls, but still
2245 //could use exports, and module. Avoid doing exports and module
2246 //work though if it just needs require.
2247 //REQUIRES the function to expect the CommonJS variables in the
2248 //order listed below.
2249 deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
2253 //If in IE 6-8 and hit an anonymous define() call, do the interactive
2255 if (useInteractive) {
2256 node = currentlyAddingScript || getInteractiveScript();
2259 name = node.getAttribute('data-requiremodule');
2261 context = contexts[node.getAttribute('data-requirecontext')];
2265 //Always save off evaluating the def call until the script onload handler.
2266 //This allows multiple modules to be in a file without prematurely
2267 //tracing dependencies, and allows for anonymous module support,
2268 //where the module name is not known until the script onload event
2269 //occurs. If no context, use the global queue, and get it processed
2270 //in the onscript load callback.
2271 (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
2280 * Executes the text. Normally just uses eval, but can be modified
2281 * to use a better, environment-specific call. Only used for transpiling
2282 * loader plugins, not for plain JS modules.
2283 * @param {String} text the text to execute/evaluate.
2285 req.exec = function (text) {
2286 /*jslint evil: true */
2290 //Set up with config info.
2296 this.requirejsVars = {
2302 if (env === 'browser') {
2304 * @license RequireJS rhino Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
2305 * Available via the MIT or new BSD license.
2306 * see: http://github.com/jrburke/requirejs for details
2309 //sloppy since eval enclosed with use strict causes problems if the source
2310 //text is not strict-compliant.
2311 /*jslint sloppy: true, evil: true */
2312 /*global require, XMLHttpRequest */
2315 require.load = function (context, moduleName, url) {
2316 var xhr = new XMLHttpRequest();
2318 xhr.open('GET', url, true);
2321 xhr.onreadystatechange = function () {
2322 if (xhr.readyState === 4) {
2323 eval(xhr.responseText);
2325 //Support anonymous modules.
2326 context.completeLoad(moduleName);
2331 } else if (env === 'rhino') {
2333 * @license RequireJS rhino Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2334 * Available via the MIT or new BSD license.
2335 * see: http://github.com/jrburke/requirejs for details
2339 /*global require: false, java: false, load: false */
2343 require.load = function (context, moduleName, url) {
2347 //Support anonymous modules.
2348 context.completeLoad(moduleName);
2352 } else if (env === 'node') {
2353 this.requirejsVars.nodeRequire = nodeRequire;
2354 require.nodeRequire = nodeRequire;
2357 * @license RequireJS node Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2358 * Available via the MIT or new BSD license.
2359 * see: http://github.com/jrburke/requirejs for details
2362 /*jslint regexp: false */
2363 /*global require: false, define: false, requirejsVars: false, process: false */
2366 * This adapter assumes that x.js has loaded it and set up
2367 * some variables. This adapter just allows limited RequireJS
2368 * usage from within the requirejs directory. The general
2369 * node adapater is r.js.
2375 var nodeReq = requirejsVars.nodeRequire,
2376 req = requirejsVars.require,
2377 def = requirejsVars.define,
2379 path = nodeReq('path'),
2381 //In Node 0.7+ existsSync is on fs.
2382 exists = fs.existsSync || path.existsSync,
2383 hasOwn = Object.prototype.hasOwnProperty;
2385 function hasProp(obj, prop) {
2386 return hasOwn.call(obj, prop);
2389 function syncTick(fn) {
2393 //Supply an implementation that allows synchronous get of a module.
2394 req.get = function (context, moduleName, relModuleMap, localRequire) {
2395 if (moduleName === "require" || moduleName === "exports" || moduleName === "module") {
2396 req.onError(new Error("Explicit require of " + moduleName + " is not allowed."));
2400 moduleMap = context.makeModuleMap(moduleName, relModuleMap, false, true);
2402 //Normalize module name, if it contains . or ..
2403 moduleName = moduleMap.id;
2405 if (hasProp(context.defined, moduleName)) {
2406 ret = context.defined[moduleName];
2408 if (ret === undefined) {
2409 //Make sure nextTick for this type of call is sync-based.
2410 oldTick = context.nextTick;
2411 context.nextTick = syncTick;
2413 if (moduleMap.prefix) {
2414 //A plugin, call requirejs to handle it. Now that
2415 //nextTick is syncTick, the require will complete
2417 localRequire([moduleMap.originalName]);
2419 //Now that plugin is loaded, can regenerate the moduleMap
2420 //to get the final, normalized ID.
2421 moduleMap = context.makeModuleMap(moduleMap.originalName, relModuleMap, false, true);
2422 moduleName = moduleMap.id;
2424 //Try to dynamically fetch it.
2425 req.load(context, moduleName, moduleMap.url);
2428 context.enable(moduleMap, relModuleMap);
2431 //Break any cycles by requiring it normally, but this will
2432 //finish synchronously
2433 require([moduleName]);
2435 //The above calls are sync, so can do the next thing safely.
2436 ret = context.defined[moduleName];
2438 context.nextTick = oldTick;
2446 req.nextTick = function (fn) {
2447 process.nextTick(fn);
2450 //Add wrapper around the code so that it gets the requirejs
2451 //API instead of the Node API, and it is done lexically so
2452 //that it survives later execution.
2453 req.makeNodeWrapper = function (contents) {
2454 return '(function (require, requirejs, define) { ' +
2456 '\n}(requirejsVars.require, requirejsVars.requirejs, requirejsVars.define));';
2459 req.load = function (context, moduleName, url) {
2461 config = context.config;
2463 if (config.shim[moduleName] && (!config.suppress || !config.suppress.nodeShim)) {
2464 console.warn('Shim config not supported in Node, may or may not work. Detected ' +
2465 'for module: ' + moduleName);
2469 contents = fs.readFileSync(url, 'utf8');
2471 contents = req.makeNodeWrapper(contents);
2473 vm.runInThisContext(contents, fs.realpathSync(url));
2475 err = new Error('Evaluating ' + url + ' as module "' +
2476 moduleName + '" failed with error: ' + e);
2477 err.originalError = e;
2478 err.moduleName = moduleName;
2480 return req.onError(err);
2483 def(moduleName, function () {
2484 //Get the original name, since relative requires may be
2485 //resolved differently in node (issue #202). Also, if relative,
2486 //make it relative to the URL of the item requesting it
2489 map = hasProp(context.registry, moduleName) &&
2490 context.registry[moduleName].map,
2491 parentMap = map && map.parentMap,
2492 originalName = map && map.originalName;
2494 if (originalName.charAt(0) === '.' && parentMap) {
2495 dirName = parentMap.url.split('/');
2497 originalName = dirName.join('/') + '/' + originalName;
2501 return (context.config.nodeRequire || req.nodeRequire)(originalName);
2503 err = new Error('Tried loading "' + moduleName + '" at ' +
2504 url + ' then tried node\'s require("' +
2505 originalName + '") and it failed ' +
2506 'with error: ' + e);
2507 err.originalError = e;
2508 err.moduleName = originalName;
2509 return req.onError(err);
2514 //Support anonymous modules.
2515 context.completeLoad(moduleName);
2518 //Override to provide the function wrapper for define/require.
2519 req.exec = function (text) {
2520 /*jslint evil: true */
2521 text = req.makeNodeWrapper(text);
2526 } else if (env === 'xpconnect') {
2528 * @license RequireJS xpconnect Copyright (c) 2013, The Dojo Foundation All Rights Reserved.
2529 * Available via the MIT or new BSD license.
2530 * see: http://github.com/jrburke/requirejs for details
2534 /*global require, load */
2538 require.load = function (context, moduleName, url) {
2542 //Support anonymous modules.
2543 context.completeLoad(moduleName);
2550 //Support a default file name to execute. Useful for hosted envs
2551 //like Joyent where it defaults to a server.js as the only executed
2552 //script. But only do it if this is not an optimization run.
2553 if (commandOption !== 'o' && (!fileName || !jsSuffixRegExp.test(fileName))) {
2554 fileName = 'main.js';
2558 * Loads the library files that can be used for the optimizer, or for other
2561 function loadLib() {
2563 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2564 * Available via the MIT or new BSD license.
2565 * see: http://github.com/jrburke/requirejs for details
2568 /*jslint strict: false */
2569 /*global Packages: false, process: false, window: false, navigator: false,
2570 document: false, define: false */
2573 * A plugin that modifies any /env/ path to be the right path based on
2574 * the host environment. Right now only works for Node, Rhino and browser.
2577 var pathRegExp = /(\/|^)env\/|\{env\}/,
2580 if (typeof Packages !== 'undefined') {
2582 } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
2584 } else if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') ||
2585 (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) {
2587 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) {
2596 load: function (name, req, load, config) {
2597 //Allow override in the config.
2602 name = name.replace(pathRegExp, function (match, prefix) {
2603 if (match.indexOf('{') === -1) {
2604 return prefix + env + '/';
2610 req([name], function (mod) {
2616 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
2617 * Available via the MIT or new BSD license.
2618 * see: http://github.com/jrburke/requirejs for details
2621 /*jslint plusplus: true */
2624 define('lang', function () {
2628 hasOwn = Object.prototype.hasOwnProperty;
2630 function hasProp(obj, prop) {
2631 return hasOwn.call(obj, prop);
2635 backSlashRegExp: /\\/g,
2636 ostring: Object.prototype.toString,
2638 isArray: Array.isArray || function (it) {
2639 return lang.ostring.call(it) === "[object Array]";
2642 isFunction: function(it) {
2643 return lang.ostring.call(it) === "[object Function]";
2646 isRegExp: function(it) {
2647 return it && it instanceof RegExp;
2652 //returns true if the object does not have an own property prop,
2653 //or if it does, it is a falsy value.
2654 falseProp: function (obj, prop) {
2655 return !hasProp(obj, prop) || !obj[prop];
2658 //gets own property value for given prop on object
2659 getOwn: function (obj, prop) {
2660 return hasProp(obj, prop) && obj[prop];
2663 _mixin: function(dest, source, override){
2665 for (name in source) {
2666 if(source.hasOwnProperty(name)
2667 && (override || !dest.hasOwnProperty(name))) {
2668 dest[name] = source[name];
2672 return dest; // Object
2676 * mixin({}, obj1, obj2) is allowed. If the last argument is a boolean,
2677 * then the source objects properties are force copied over to dest.
2679 mixin: function(dest){
2680 var parameters = Array.prototype.slice.call(arguments),
2683 if (!dest) { dest = {}; }
2685 if (parameters.length > 2 && typeof arguments[parameters.length-1] === 'boolean') {
2686 override = parameters.pop();
2689 for (i = 1, l = parameters.length; i < l; i++) {
2690 lang._mixin(dest, parameters[i], override);
2692 return dest; // Object
2695 delegate: (function () {
2696 // boodman/crockford delegation w/ cornford optimization
2698 return function (obj, props) {
2699 TMP.prototype = obj;
2700 var tmp = new TMP();
2701 TMP.prototype = null;
2703 lang.mixin(tmp, props);
2705 return tmp; // Object
2710 * Helper function for iterating over an array. If the func returns
2711 * a true value, it will break out of the loop.
2713 each: function each(ary, func) {
2716 for (i = 0; i < ary.length; i += 1) {
2717 if (func(ary[i], i, ary)) {
2725 * Cycles over properties in an object and calls a function for each
2726 * property value. If the function returns a truthy value, then the
2727 * iteration is stopped.
2729 eachProp: function eachProp(obj, func) {
2732 if (hasProp(obj, prop)) {
2733 if (func(obj[prop], prop)) {
2740 //Similar to Function.prototype.bind, but the "this" object is specified
2741 //first, since it is easier to read/figure out what "this" will be.
2742 bind: function bind(obj, fn) {
2743 return function () {
2744 return fn.apply(obj, arguments);
2748 //Escapes a content string to be be a string that has characters escaped
2749 //for inclusion as part of a JS string.
2750 jsEscape: function (content) {
2751 return content.replace(/(["'\\])/g, '\\$1')
2752 .replace(/[\f]/g, "\\f")
2753 .replace(/[\b]/g, "\\b")
2754 .replace(/[\n]/g, "\\n")
2755 .replace(/[\t]/g, "\\t")
2756 .replace(/[\r]/g, "\\r");
2762 * prim 0.0.1 Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved.
2763 * Available via the MIT or new BSD license.
2764 * see: http://github.com/requirejs/prim for details
2767 /*global setImmediate, process, setTimeout, define, module */
2769 //Set prime.hideResolutionConflict = true to allow "resolution-races"
2770 //in promise-tests to pass.
2771 //Since the goal of prim is to be a small impl for trusted code, it is
2772 //more important to normally throw in this case so that we can find
2773 //logic errors quicker.
2778 var op = Object.prototype,
2779 hasOwn = op.hasOwnProperty;
2781 function hasProp(obj, prop) {
2782 return hasOwn.call(obj, prop);
2786 * Helper function for iterating over an array. If the func returns
2787 * a true value, it will break out of the loop.
2789 function each(ary, func) {
2792 for (i = 0; i < ary.length; i += 1) {
2794 func(ary[i], i, ary);
2801 if (hasProp(p, 'e') || hasProp(p, 'v')) {
2802 if (!prim.hideResolutionConflict) {
2803 throw new Error('nope');
2810 function notify(ary, value) {
2811 prim.nextTick(function () {
2812 each(ary, function (item) {
2818 prim = function prim() {
2824 callback: function (yes, no) {
2829 if (hasProp(p, 'v')) {
2830 prim.nextTick(function () {
2838 errback: function (no) {
2839 if (hasProp(p, 'e')) {
2840 prim.nextTick(function () {
2848 finished: function () {
2849 return hasProp(p, 'e') || hasProp(p, 'v');
2852 rejected: function () {
2853 return hasProp(p, 'e');
2856 resolve: function (v) {
2863 reject: function (e) {
2871 start: function (fn) {
2873 return p.promise.then(fn);
2877 then: function (yes, no) {
2880 p.callback(function (v) {
2882 if (yes && typeof yes === 'function') {
2887 v.then(next.resolve, next.reject);
2898 if (!no || typeof no !== 'function') {
2903 if (err && err.then) {
2904 err.then(next.resolve, next.reject);
2914 return next.promise;
2917 fail: function (no) {
2918 return p.promise.then(null, no);
2922 p.errback(function (e) {
2930 prim.serial = function (ary) {
2931 var result = prim().resolve().promise;
2932 each(ary, function (item) {
2933 result = result.then(function () {
2940 prim.nextTick = typeof setImmediate === 'function' ? setImmediate :
2941 (typeof process !== 'undefined' && process.nextTick ?
2942 process.nextTick : (typeof setTimeout !== 'undefined' ?
2949 if (typeof define === 'function' && define.amd) {
2950 define('prim', function () { return prim; });
2951 } else if (typeof module !== 'undefined' && module.exports) {
2952 module.exports = prim;
2955 if(env === 'browser') {
2957 * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
2958 * Available via the MIT or new BSD license.
2959 * see: http://github.com/jrburke/requirejs for details
2962 /*jslint strict: false */
2963 /*global define: false, load: false */
2965 //Just a stub for use with uglify's consolidator.js
2966 define('browser/assert', function () {
2972 if(env === 'node') {
2974 * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
2975 * Available via the MIT or new BSD license.
2976 * see: http://github.com/jrburke/requirejs for details
2979 /*jslint strict: false */
2980 /*global define: false, load: false */
2982 //Needed so that rhino/assert can return a stub for uglify's consolidator.js
2983 define('node/assert', ['assert'], function (assert) {
2989 if(env === 'rhino') {
2991 * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
2992 * Available via the MIT or new BSD license.
2993 * see: http://github.com/jrburke/requirejs for details
2996 /*jslint strict: false */
2997 /*global define: false, load: false */
2999 //Just a stub for use with uglify's consolidator.js
3000 define('rhino/assert', function () {
3006 if(env === 'xpconnect') {
3008 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved.
3009 * Available via the MIT or new BSD license.
3010 * see: http://github.com/jrburke/requirejs for details
3013 /*jslint strict: false */
3014 /*global define: false, load: false */
3016 //Just a stub for use with uglify's consolidator.js
3017 define('xpconnect/assert', function () {
3023 if(env === 'browser') {
3025 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3026 * Available via the MIT or new BSD license.
3027 * see: http://github.com/jrburke/requirejs for details
3030 /*jslint strict: false */
3031 /*global define: false, process: false */
3033 define('browser/args', function () {
3034 //Always expect config via an API call
3040 if(env === 'node') {
3042 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3043 * Available via the MIT or new BSD license.
3044 * see: http://github.com/jrburke/requirejs for details
3047 /*jslint strict: false */
3048 /*global define: false, process: false */
3050 define('node/args', function () {
3051 //Do not return the "node" or "r.js" arguments
3052 var args = process.argv.slice(2);
3054 //Ignore any command option used for main x.js branching
3055 if (args[0] && args[0].indexOf('-') === 0) {
3056 args = args.slice(1);
3064 if(env === 'rhino') {
3066 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3067 * Available via the MIT or new BSD license.
3068 * see: http://github.com/jrburke/requirejs for details
3071 /*jslint strict: false */
3072 /*global define: false, process: false */
3074 var jsLibRhinoArgs = (typeof rhinoArgs !== 'undefined' && rhinoArgs) || [].concat(Array.prototype.slice.call(arguments, 0));
3076 define('rhino/args', function () {
3077 var args = jsLibRhinoArgs;
3079 //Ignore any command option used for main x.js branching
3080 if (args[0] && args[0].indexOf('-') === 0) {
3081 args = args.slice(1);
3089 if(env === 'xpconnect') {
3091 * @license Copyright (c) 2013, 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 strict: false */
3097 /*global define, xpconnectArgs */
3099 var jsLibXpConnectArgs = (typeof xpconnectArgs !== 'undefined' && xpconnectArgs) || [].concat(Array.prototype.slice.call(arguments, 0));
3101 define('xpconnect/args', function () {
3102 var args = jsLibXpConnectArgs;
3104 //Ignore any command option used for main x.js branching
3105 if (args[0] && args[0].indexOf('-') === 0) {
3106 args = args.slice(1);
3114 if(env === 'browser') {
3116 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3117 * Available via the MIT or new BSD license.
3118 * see: http://github.com/jrburke/requirejs for details
3121 /*jslint strict: false */
3122 /*global define: false, console: false */
3124 define('browser/load', ['./file'], function (file) {
3125 function load(fileName) {
3126 eval(file.readFile(fileName));
3134 if(env === 'node') {
3136 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3137 * Available via the MIT or new BSD license.
3138 * see: http://github.com/jrburke/requirejs for details
3141 /*jslint strict: false */
3142 /*global define: false, console: false */
3144 define('node/load', ['fs'], function (fs) {
3145 function load(fileName) {
3146 var contents = fs.readFileSync(fileName, 'utf8');
3147 process.compile(contents, fileName);
3155 if(env === 'rhino') {
3157 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3158 * Available via the MIT or new BSD license.
3159 * see: http://github.com/jrburke/requirejs for details
3162 /*jslint strict: false */
3163 /*global define: false, load: false */
3165 define('rhino/load', function () {
3171 if(env === 'xpconnect') {
3173 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved.
3174 * Available via the MIT or new BSD license.
3175 * see: http://github.com/jrburke/requirejs for details
3178 /*jslint strict: false */
3179 /*global define: false, load: false */
3181 define('xpconnect/load', function () {
3187 if(env === 'browser') {
3189 * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
3190 * Available via the MIT or new BSD license.
3191 * see: http://github.com/jrburke/requirejs for details
3194 /*jslint sloppy: true, nomen: true */
3195 /*global require, define, console, XMLHttpRequest, requirejs, location */
3197 define('browser/file', ['prim'], function (prim) {
3200 currDirRegExp = /^\.(\/|$)/;
3202 function frontSlash(path) {
3203 return path.replace(/\\/g, '/');
3206 function exists(path) {
3207 var status, xhr = new XMLHttpRequest();
3209 //Oh yeah, that is right SYNC IO. Behold its glory
3210 //and horrible blocking behavior.
3211 xhr.open('HEAD', path, false);
3213 status = xhr.status;
3215 return status === 200 || status === 304;
3218 function mkDir(dir) {
3219 console.log('mkDir is no-op in browser');
3222 function mkFullDir(dir) {
3223 console.log('mkFullDir is no-op in browser');
3227 backSlashRegExp: /\\/g,
3228 exclusionRegExp: /^\./,
3229 getLineSeparator: function () {
3233 exists: function (fileName) {
3234 return exists(fileName);
3237 parent: function (fileName) {
3238 var parts = fileName.split('/');
3240 return parts.join('/');
3244 * Gets the absolute file path as a string, normalized
3245 * to using front slashes for path separators.
3246 * @param {String} fileName
3248 absPath: function (fileName) {
3250 if (currDirRegExp.test(fileName)) {
3251 dir = frontSlash(location.href);
3252 if (dir.indexOf('/') !== -1) {
3253 dir = dir.split('/');
3255 //Pull off protocol and host, just want
3256 //to allow paths (other build parts, like
3257 //require._isSupportedBuildUrl do not support
3258 //full URLs), but a full path from
3263 dir = '/' + dir.join('/');
3266 fileName = dir + fileName.substring(1);
3272 normalize: function (fileName) {
3276 isFile: function (path) {
3280 isDirectory: function (path) {
3284 getFilteredFileList: function (startDir, regExpFilters, makeUnixPaths) {
3285 console.log('file.getFilteredFileList is no-op in browser');
3288 copyDir: function (srcDir, destDir, regExpFilter, onlyCopyNew) {
3289 console.log('file.copyDir is no-op in browser');
3293 copyFile: function (srcFileName, destFileName, onlyCopyNew) {
3294 console.log('file.copyFile is no-op in browser');
3298 * Renames a file. May fail if "to" already exists or is on another drive.
3300 renameFile: function (from, to) {
3301 console.log('file.renameFile is no-op in browser');
3305 * Reads a *text* file.
3307 readFile: function (path, encoding) {
3308 var xhr = new XMLHttpRequest();
3310 //Oh yeah, that is right SYNC IO. Behold its glory
3311 //and horrible blocking behavior.
3312 xhr.open('GET', path, false);
3315 return xhr.responseText;
3318 readFileAsync: function (path, encoding) {
3319 var xhr = new XMLHttpRequest(),
3322 xhr.open('GET', path, true);
3325 xhr.onreadystatechange = function () {
3326 if (xhr.readyState === 4) {
3327 if (xhr.status > 400) {
3328 d.reject(new Error('Status: ' + xhr.status + ': ' + xhr.statusText));
3330 d.resolve(xhr.responseText);
3338 saveUtf8File: function (fileName, fileContents) {
3339 //summary: saves a *text* file using UTF-8 encoding.
3340 file.saveFile(fileName, fileContents, "utf8");
3343 saveFile: function (fileName, fileContents, encoding) {
3344 requirejs.browser.saveFile(fileName, fileContents, encoding);
3347 deleteFile: function (fileName) {
3348 console.log('file.deleteFile is no-op in browser');
3352 * Deletes any empty directories under the given directory.
3354 deleteEmptyDirs: function (startDir) {
3355 console.log('file.deleteEmptyDirs is no-op in browser');
3365 if(env === 'node') {
3367 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3368 * Available via the MIT or new BSD license.
3369 * see: http://github.com/jrburke/requirejs for details
3372 /*jslint plusplus: false, octal:false, strict: false */
3373 /*global define: false, process: false */
3375 define('node/file', ['fs', 'path', 'prim'], function (fs, path, prim) {
3377 var isWindows = process.platform === 'win32',
3378 windowsDriveRegExp = /^[a-zA-Z]\:\/$/,
3381 function frontSlash(path) {
3382 return path.replace(/\\/g, '/');
3385 function exists(path) {
3386 if (isWindows && path.charAt(path.length - 1) === '/' &&
3387 path.charAt(path.length - 2) !== ':') {
3388 path = path.substring(0, path.length - 1);
3399 function mkDir(dir) {
3400 if (!exists(dir) && (!isWindows || !windowsDriveRegExp.test(dir))) {
3401 fs.mkdirSync(dir, 511);
3405 function mkFullDir(dir) {
3406 var parts = dir.split('/'),
3410 parts.forEach(function (part) {
3411 //First part may be empty string if path starts with a slash.
3412 currDir += part + '/';
3422 backSlashRegExp: /\\/g,
3423 exclusionRegExp: /^\./,
3424 getLineSeparator: function () {
3428 exists: function (fileName) {
3429 return exists(fileName);
3432 parent: function (fileName) {
3433 var parts = fileName.split('/');
3435 return parts.join('/');
3439 * Gets the absolute file path as a string, normalized
3440 * to using front slashes for path separators.
3441 * @param {String} fileName
3443 absPath: function (fileName) {
3444 return frontSlash(path.normalize(frontSlash(fs.realpathSync(fileName))));
3447 normalize: function (fileName) {
3448 return frontSlash(path.normalize(fileName));
3451 isFile: function (path) {
3452 return fs.statSync(path).isFile();
3455 isDirectory: function (path) {
3456 return fs.statSync(path).isDirectory();
3459 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths) {
3460 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
3461 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
3462 //and it will be treated as the "include" case.
3463 //Ignores files/directories that start with a period (.) unless exclusionRegExp
3464 //is set to another value.
3465 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
3466 i, stat, filePath, ok, dirFiles, fileName;
3470 regExpInclude = regExpFilters.include || regExpFilters;
3471 regExpExclude = regExpFilters.exclude || null;
3473 if (file.exists(topDir)) {
3474 dirFileArray = fs.readdirSync(topDir);
3475 for (i = 0; i < dirFileArray.length; i++) {
3476 fileName = dirFileArray[i];
3477 filePath = path.join(topDir, fileName);
3478 stat = fs.statSync(filePath);
3479 if (stat.isFile()) {
3480 if (makeUnixPaths) {
3481 //Make sure we have a JS string.
3482 if (filePath.indexOf("/") === -1) {
3483 filePath = frontSlash(filePath);
3488 if (regExpInclude) {
3489 ok = filePath.match(regExpInclude);
3491 if (ok && regExpExclude) {
3492 ok = !filePath.match(regExpExclude);
3495 if (ok && (!file.exclusionRegExp ||
3496 !file.exclusionRegExp.test(fileName))) {
3497 files.push(filePath);
3499 } else if (stat.isDirectory() &&
3500 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileName))) {
3501 dirFiles = this.getFilteredFileList(filePath, regExpFilters, makeUnixPaths);
3502 files.push.apply(files, dirFiles);
3507 return files; //Array
3510 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
3511 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
3512 //file should be copied. Returns a list file name strings of the destinations that were copied.
3513 regExpFilter = regExpFilter || /\w/;
3515 //Normalize th directory names, but keep front slashes.
3516 //path module on windows now returns backslashed paths.
3517 srcDir = frontSlash(path.normalize(srcDir));
3518 destDir = frontSlash(path.normalize(destDir));
3520 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
3521 copiedFiles = [], i, srcFileName, destFileName;
3523 for (i = 0; i < fileNames.length; i++) {
3524 srcFileName = fileNames[i];
3525 destFileName = srcFileName.replace(srcDir, destDir);
3527 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
3528 copiedFiles.push(destFileName);
3532 return copiedFiles.length ? copiedFiles : null; //Array or null
3535 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
3536 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
3537 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
3540 //logger.trace("Src filename: " + srcFileName);
3541 //logger.trace("Dest filename: " + destFileName);
3543 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
3546 if (file.exists(destFileName) && fs.statSync(destFileName).mtime.getTime() >= fs.statSync(srcFileName).mtime.getTime()) {
3547 return false; //Boolean
3551 //Make sure destination dir exists.
3552 parentDir = path.dirname(destFileName);
3553 if (!file.exists(parentDir)) {
3554 mkFullDir(parentDir);
3557 fs.writeFileSync(destFileName, fs.readFileSync(srcFileName, 'binary'), 'binary');
3559 return true; //Boolean
3563 * Renames a file. May fail if "to" already exists or is on another drive.
3565 renameFile: function (from, to) {
3566 return fs.renameSync(from, to);
3570 * Reads a *text* file.
3572 readFile: function (/*String*/path, /*String?*/encoding) {
3573 if (encoding === 'utf-8') {
3580 var text = fs.readFileSync(path, encoding);
3582 //Hmm, would not expect to get A BOM, but it seems to happen,
3583 //remove it just in case.
3584 if (text.indexOf('\uFEFF') === 0) {
3585 text = text.substring(1, text.length);
3591 readFileAsync: function (path, encoding) {
3594 d.resolve(file.readFile(path, encoding));
3601 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
3602 //summary: saves a *text* file using UTF-8 encoding.
3603 file.saveFile(fileName, fileContents, "utf8");
3606 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
3607 //summary: saves a *text* file.
3610 if (encoding === 'utf-8') {
3617 //Make sure destination directories exist.
3618 parentDir = path.dirname(fileName);
3619 if (!file.exists(parentDir)) {
3620 mkFullDir(parentDir);
3623 fs.writeFileSync(fileName, fileContents, encoding);
3626 deleteFile: function (/*String*/fileName) {
3627 //summary: deletes a file or directory if it exists.
3629 if (file.exists(fileName)) {
3630 stat = fs.statSync(fileName);
3631 if (stat.isDirectory()) {
3632 files = fs.readdirSync(fileName);
3633 for (i = 0; i < files.length; i++) {
3634 this.deleteFile(path.join(fileName, files[i]));
3636 fs.rmdirSync(fileName);
3638 fs.unlinkSync(fileName);
3645 * Deletes any empty directories under the given directory.
3647 deleteEmptyDirs: function (startDir) {
3648 var dirFileArray, i, fileName, filePath, stat;
3650 if (file.exists(startDir)) {
3651 dirFileArray = fs.readdirSync(startDir);
3652 for (i = 0; i < dirFileArray.length; i++) {
3653 fileName = dirFileArray[i];
3654 filePath = path.join(startDir, fileName);
3655 stat = fs.statSync(filePath);
3656 if (stat.isDirectory()) {
3657 file.deleteEmptyDirs(filePath);
3661 //If directory is now empty, remove it.
3662 if (fs.readdirSync(startDir).length === 0) {
3663 file.deleteFile(startDir);
3675 if(env === 'rhino') {
3677 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3678 * Available via the MIT or new BSD license.
3679 * see: http://github.com/jrburke/requirejs for details
3681 //Helper functions to deal with file I/O.
3683 /*jslint plusplus: false */
3684 /*global java: false, define: false */
3686 define('rhino/file', ['prim'], function (prim) {
3688 backSlashRegExp: /\\/g,
3690 exclusionRegExp: /^\./,
3692 getLineSeparator: function () {
3693 return file.lineSeparator;
3696 lineSeparator: java.lang.System.getProperty("line.separator"), //Java String
3698 exists: function (fileName) {
3699 return (new java.io.File(fileName)).exists();
3702 parent: function (fileName) {
3703 return file.absPath((new java.io.File(fileName)).getParentFile());
3706 normalize: function (fileName) {
3707 return file.absPath(fileName);
3710 isFile: function (path) {
3711 return (new java.io.File(path)).isFile();
3714 isDirectory: function (path) {
3715 return (new java.io.File(path)).isDirectory();
3719 * Gets the absolute file path as a string, normalized
3720 * to using front slashes for path separators.
3721 * @param {java.io.File||String} file
3723 absPath: function (fileObj) {
3724 if (typeof fileObj === "string") {
3725 fileObj = new java.io.File(fileObj);
3727 return (fileObj.getCanonicalPath() + "").replace(file.backSlashRegExp, "/");
3730 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) {
3731 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
3732 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
3733 //and it will be treated as the "include" case.
3734 //Ignores files/directories that start with a period (.) unless exclusionRegExp
3735 //is set to another value.
3736 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
3737 i, fileObj, filePath, ok, dirFiles;
3740 if (!startDirIsJavaObject) {
3741 topDir = new java.io.File(startDir);
3744 regExpInclude = regExpFilters.include || regExpFilters;
3745 regExpExclude = regExpFilters.exclude || null;
3747 if (topDir.exists()) {
3748 dirFileArray = topDir.listFiles();
3749 for (i = 0; i < dirFileArray.length; i++) {
3750 fileObj = dirFileArray[i];
3751 if (fileObj.isFile()) {
3752 filePath = fileObj.getPath();
3753 if (makeUnixPaths) {
3754 //Make sure we have a JS string.
3755 filePath = String(filePath);
3756 if (filePath.indexOf("/") === -1) {
3757 filePath = filePath.replace(/\\/g, "/");
3762 if (regExpInclude) {
3763 ok = filePath.match(regExpInclude);
3765 if (ok && regExpExclude) {
3766 ok = !filePath.match(regExpExclude);
3769 if (ok && (!file.exclusionRegExp ||
3770 !file.exclusionRegExp.test(fileObj.getName()))) {
3771 files.push(filePath);
3773 } else if (fileObj.isDirectory() &&
3774 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.getName()))) {
3775 dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true);
3776 files.push.apply(files, dirFiles);
3781 return files; //Array
3784 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
3785 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
3786 //file should be copied. Returns a list file name strings of the destinations that were copied.
3787 regExpFilter = regExpFilter || /\w/;
3789 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
3790 copiedFiles = [], i, srcFileName, destFileName;
3792 for (i = 0; i < fileNames.length; i++) {
3793 srcFileName = fileNames[i];
3794 destFileName = srcFileName.replace(srcDir, destDir);
3796 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
3797 copiedFiles.push(destFileName);
3801 return copiedFiles.length ? copiedFiles : null; //Array or null
3804 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
3805 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
3806 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
3807 var destFile = new java.io.File(destFileName), srcFile, parentDir,
3808 srcChannel, destChannel;
3810 //logger.trace("Src filename: " + srcFileName);
3811 //logger.trace("Dest filename: " + destFileName);
3813 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
3816 srcFile = new java.io.File(srcFileName);
3817 if (destFile.exists() && destFile.lastModified() >= srcFile.lastModified()) {
3818 return false; //Boolean
3822 //Make sure destination dir exists.
3823 parentDir = destFile.getParentFile();
3824 if (!parentDir.exists()) {
3825 if (!parentDir.mkdirs()) {
3826 throw "Could not create directory: " + parentDir.getCanonicalPath();
3830 //Java's version of copy file.
3831 srcChannel = new java.io.FileInputStream(srcFileName).getChannel();
3832 destChannel = new java.io.FileOutputStream(destFileName).getChannel();
3833 destChannel.transferFrom(srcChannel, 0, srcChannel.size());
3835 destChannel.close();
3837 return true; //Boolean
3841 * Renames a file. May fail if "to" already exists or is on another drive.
3843 renameFile: function (from, to) {
3844 return (new java.io.File(from)).renameTo((new java.io.File(to)));
3847 readFile: function (/*String*/path, /*String?*/encoding) {
3848 //A file read function that can deal with BOMs
3849 encoding = encoding || "utf-8";
3850 var fileObj = new java.io.File(path),
3851 input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(fileObj), encoding)),
3854 stringBuffer = new java.lang.StringBuffer();
3855 line = input.readLine();
3857 // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
3858 // http://www.unicode.org/faq/utf_bom.html
3860 // 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:
3861 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
3862 if (line && line.length() && line.charAt(0) === 0xfeff) {
3863 // Eat the BOM, since we've already found the encoding on this file,
3864 // and we plan to concatenating this buffer with others; the BOM should
3865 // only appear at the top of a file.
3866 line = line.substring(1);
3868 while (line !== null) {
3869 stringBuffer.append(line);
3870 stringBuffer.append(file.lineSeparator);
3871 line = input.readLine();
3873 //Make sure we return a JavaScript string and not a Java string.
3874 return String(stringBuffer.toString()); //String
3880 readFileAsync: function (path, encoding) {
3883 d.resolve(file.readFile(path, encoding));
3890 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
3891 //summary: saves a file using UTF-8 encoding.
3892 file.saveFile(fileName, fileContents, "utf-8");
3895 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
3896 //summary: saves a file.
3897 var outFile = new java.io.File(fileName), outWriter, parentDir, os;
3899 parentDir = outFile.getAbsoluteFile().getParentFile();
3900 if (!parentDir.exists()) {
3901 if (!parentDir.mkdirs()) {
3902 throw "Could not create directory: " + parentDir.getAbsolutePath();
3907 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
3909 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
3912 os = new java.io.BufferedWriter(outWriter);
3914 os.write(fileContents);
3920 deleteFile: function (/*String*/fileName) {
3921 //summary: deletes a file or directory if it exists.
3922 var fileObj = new java.io.File(fileName), files, i;
3923 if (fileObj.exists()) {
3924 if (fileObj.isDirectory()) {
3925 files = fileObj.listFiles();
3926 for (i = 0; i < files.length; i++) {
3927 this.deleteFile(files[i]);
3930 fileObj["delete"]();
3935 * Deletes any empty directories under the given directory.
3936 * The startDirIsJavaObject is private to this implementation's
3939 deleteEmptyDirs: function (startDir, startDirIsJavaObject) {
3940 var topDir = startDir,
3941 dirFileArray, i, fileObj;
3943 if (!startDirIsJavaObject) {
3944 topDir = new java.io.File(startDir);
3947 if (topDir.exists()) {
3948 dirFileArray = topDir.listFiles();
3949 for (i = 0; i < dirFileArray.length; i++) {
3950 fileObj = dirFileArray[i];
3951 if (fileObj.isDirectory()) {
3952 file.deleteEmptyDirs(fileObj, true);
3956 //If the directory is empty now, delete it.
3957 if (topDir.listFiles().length === 0) {
3958 file.deleteFile(String(topDir.getPath()));
3969 if(env === 'xpconnect') {
3971 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved.
3972 * Available via the MIT or new BSD license.
3973 * see: http://github.com/jrburke/requirejs for details
3975 //Helper functions to deal with file I/O.
3977 /*jslint plusplus: false */
3978 /*global define, Components, xpcUtil */
3980 define('xpconnect/file', ['prim'], function (prim) {
3982 Cc = Components.classes,
3983 Ci = Components.interfaces,
3984 //Depends on xpcUtil which is set up in x.js
3985 xpfile = xpcUtil.xpfile;
3987 function mkFullDir(dirObj) {
3988 //1 is DIRECTORY_TYPE, 511 is 0777 permissions
3989 if (!dirObj.exists()) {
3990 dirObj.create(1, 511);
3995 backSlashRegExp: /\\/g,
3997 exclusionRegExp: /^\./,
3999 getLineSeparator: function () {
4000 return file.lineSeparator;
4003 lineSeparator: ('@mozilla.org/windows-registry-key;1' in Cc) ?
4006 exists: function (fileName) {
4007 return xpfile(fileName).exists();
4010 parent: function (fileName) {
4011 return xpfile(fileName).parent;
4014 normalize: function (fileName) {
4015 return file.absPath(fileName);
4018 isFile: function (path) {
4019 return xpfile(path).isFile();
4022 isDirectory: function (path) {
4023 return xpfile(path).isDirectory();
4027 * Gets the absolute file path as a string, normalized
4028 * to using front slashes for path separators.
4029 * @param {java.io.File||String} file
4031 absPath: function (fileObj) {
4032 if (typeof fileObj === "string") {
4033 fileObj = xpfile(fileObj);
4035 return fileObj.path;
4038 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsObject) {
4039 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
4040 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
4041 //and it will be treated as the "include" case.
4042 //Ignores files/directories that start with a period (.) unless exclusionRegExp
4043 //is set to another value.
4044 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
4045 fileObj, filePath, ok, dirFiles;
4048 if (!startDirIsObject) {
4049 topDir = xpfile(startDir);
4052 regExpInclude = regExpFilters.include || regExpFilters;
4053 regExpExclude = regExpFilters.exclude || null;
4055 if (topDir.exists()) {
4056 dirFileArray = topDir.directoryEntries;
4057 while (dirFileArray.hasMoreElements()) {
4058 fileObj = dirFileArray.getNext().QueryInterface(Ci.nsILocalFile);
4059 if (fileObj.isFile()) {
4060 filePath = fileObj.path;
4061 if (makeUnixPaths) {
4062 if (filePath.indexOf("/") === -1) {
4063 filePath = filePath.replace(/\\/g, "/");
4068 if (regExpInclude) {
4069 ok = filePath.match(regExpInclude);
4071 if (ok && regExpExclude) {
4072 ok = !filePath.match(regExpExclude);
4075 if (ok && (!file.exclusionRegExp ||
4076 !file.exclusionRegExp.test(fileObj.leafName))) {
4077 files.push(filePath);
4079 } else if (fileObj.isDirectory() &&
4080 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.leafName))) {
4081 dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true);
4082 files.push.apply(files, dirFiles);
4087 return files; //Array
4090 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
4091 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
4092 //file should be copied. Returns a list file name strings of the destinations that were copied.
4093 regExpFilter = regExpFilter || /\w/;
4095 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
4096 copiedFiles = [], i, srcFileName, destFileName;
4098 for (i = 0; i < fileNames.length; i += 1) {
4099 srcFileName = fileNames[i];
4100 destFileName = srcFileName.replace(srcDir, destDir);
4102 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
4103 copiedFiles.push(destFileName);
4107 return copiedFiles.length ? copiedFiles : null; //Array or null
4110 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
4111 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
4112 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
4113 var destFile = xpfile(destFileName),
4114 srcFile = xpfile(srcFileName);
4116 //logger.trace("Src filename: " + srcFileName);
4117 //logger.trace("Dest filename: " + destFileName);
4119 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
4122 if (destFile.exists() && destFile.lastModifiedTime >= srcFile.lastModifiedTime) {
4123 return false; //Boolean
4127 srcFile.copyTo(destFile.parent, destFile.leafName);
4129 return true; //Boolean
4133 * Renames a file. May fail if "to" already exists or is on another drive.
4135 renameFile: function (from, to) {
4136 var toFile = xpfile(to);
4137 return xpfile(from).moveTo(toFile.parent, toFile.leafName);
4140 readFile: xpcUtil.readFile,
4142 readFileAsync: function (path, encoding) {
4145 d.resolve(file.readFile(path, encoding));
4152 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
4153 //summary: saves a file using UTF-8 encoding.
4154 file.saveFile(fileName, fileContents, "utf-8");
4157 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
4158 var outStream, convertStream,
4159 fileObj = xpfile(fileName);
4161 mkFullDir(fileObj.parent);
4164 outStream = Cc['@mozilla.org/network/file-output-stream;1']
4165 .createInstance(Ci.nsIFileOutputStream);
4166 //438 is decimal for 0777
4167 outStream.init(fileObj, 0x02 | 0x08 | 0x20, 511, 0);
4169 convertStream = Cc['@mozilla.org/intl/converter-output-stream;1']
4170 .createInstance(Ci.nsIConverterOutputStream);
4172 convertStream.init(outStream, encoding, 0, 0);
4173 convertStream.writeString(fileContents);
4175 throw new Error((fileObj && fileObj.path || '') + ': ' + e);
4177 if (convertStream) {
4178 convertStream.close();
4186 deleteFile: function (/*String*/fileName) {
4187 //summary: deletes a file or directory if it exists.
4188 var fileObj = xpfile(fileName);
4189 if (fileObj.exists()) {
4190 fileObj.remove(true);
4195 * Deletes any empty directories under the given directory.
4196 * The startDirIsJavaObject is private to this implementation's
4199 deleteEmptyDirs: function (startDir, startDirIsObject) {
4200 var topDir = startDir,
4201 dirFileArray, fileObj;
4203 if (!startDirIsObject) {
4204 topDir = xpfile(startDir);
4207 if (topDir.exists()) {
4208 dirFileArray = topDir.directoryEntries;
4209 while (dirFileArray.hasMoreElements()) {
4210 fileObj = dirFileArray.getNext().QueryInterface(Ci.nsILocalFile);
4212 if (fileObj.isDirectory()) {
4213 file.deleteEmptyDirs(fileObj, true);
4217 //If the directory is empty now, delete it.
4218 dirFileArray = topDir.directoryEntries;
4219 if (!dirFileArray.hasMoreElements()) {
4220 file.deleteFile(topDir.path);
4231 if(env === 'browser') {
4233 define('browser/quit', function () {
4235 return function (code) {
4240 if(env === 'node') {
4242 define('node/quit', function () {
4244 return function (code) {
4246 var exit = function () {
4247 if (draining === 0) {
4253 if (process.stdout.bufferSize) {
4255 process.stdout.once('drain', exit);
4257 if (process.stderr.bufferSize) {
4259 process.stderr.once('drain', exit);
4267 if(env === 'rhino') {
4269 define('rhino/quit', function () {
4271 return function (code) {
4278 if(env === 'xpconnect') {
4280 define('xpconnect/quit', function () {
4282 return function (code) {
4289 if(env === 'browser') {
4291 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
4292 * Available via the MIT or new BSD license.
4293 * see: http://github.com/jrburke/requirejs for details
4296 /*jslint strict: false */
4297 /*global define: false, console: false */
4299 define('browser/print', function () {
4300 function print(msg) {
4309 if(env === 'node') {
4311 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
4312 * Available via the MIT or new BSD license.
4313 * see: http://github.com/jrburke/requirejs for details
4316 /*jslint strict: false */
4317 /*global define: false, console: false */
4319 define('node/print', function () {
4320 function print(msg) {
4329 if(env === 'rhino') {
4331 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
4332 * Available via the MIT or new BSD license.
4333 * see: http://github.com/jrburke/requirejs for details
4336 /*jslint strict: false */
4337 /*global define: false, print: false */
4339 define('rhino/print', function () {
4345 if(env === 'xpconnect') {
4347 * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved.
4348 * Available via the MIT or new BSD license.
4349 * see: http://github.com/jrburke/requirejs for details
4352 /*jslint strict: false */
4353 /*global define: false, print: false */
4355 define('xpconnect/print', function () {
4361 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
4362 * Available via the MIT or new BSD license.
4363 * see: http://github.com/jrburke/requirejs for details
4366 /*jslint nomen: false, strict: false */
4367 /*global define: false */
4369 define('logger', ['env!env/print'], function (print) {
4379 logLevel: function( level ) {
4383 trace: function (message) {
4384 if (this.level <= this.TRACE) {
4385 this._print(message);
4389 info: function (message) {
4390 if (this.level <= this.INFO) {
4391 this._print(message);
4395 warn: function (message) {
4396 if (this.level <= this.WARN) {
4397 this._print(message);
4401 error: function (message) {
4402 if (this.level <= this.ERROR) {
4403 this._print(message);
4407 _print: function (message) {
4408 this._sysPrint((this.logPrefix ? (this.logPrefix + " ") : "") + message);
4411 _sysPrint: function (message) {
4418 //Just a blank file to use when building the optimizer with the optimizer,
4419 //so that the build does not attempt to inline some env modules,
4420 //like Node's fs and path.
4423 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
4424 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
4425 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
4426 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
4427 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
4428 Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
4429 Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
4431 Redistribution and use in source and binary forms, with or without
4432 modification, are permitted provided that the following conditions are met:
4434 * Redistributions of source code must retain the above copyright
4435 notice, this list of conditions and the following disclaimer.
4436 * Redistributions in binary form must reproduce the above copyright
4437 notice, this list of conditions and the following disclaimer in the
4438 documentation and/or other materials provided with the distribution.
4440 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4441 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4442 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4443 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
4444 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4445 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4446 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4447 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4448 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
4449 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4452 /*jslint bitwise:true plusplus:true */
4453 /*global esprima:true, define:true, exports:true, window: true,
4454 throwError: true, createLiteral: true, generateStatement: true,
4455 parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
4456 parseFunctionDeclaration: true, parseFunctionExpression: true,
4457 parseFunctionSourceElements: true, parseVariableIdentifier: true,
4458 parseLeftHandSideExpression: true,
4459 parseStatement: true, parseSourceElement: true */
4461 (function (root, factory) {
4464 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
4465 // Rhino, and plain browser loading.
4466 if (typeof define === 'function' && define.amd) {
4467 define('esprima', ['exports'], factory);
4468 } else if (typeof exports !== 'undefined') {
4471 factory((root.esprima = {}));
4473 }(this, function (exports) {
4504 TokenName[Token.BooleanLiteral] = 'Boolean';
4505 TokenName[Token.EOF] = '<end>';
4506 TokenName[Token.Identifier] = 'Identifier';
4507 TokenName[Token.Keyword] = 'Keyword';
4508 TokenName[Token.NullLiteral] = 'Null';
4509 TokenName[Token.NumericLiteral] = 'Numeric';
4510 TokenName[Token.Punctuator] = 'Punctuator';
4511 TokenName[Token.StringLiteral] = 'String';
4514 AssignmentExpression: 'AssignmentExpression',
4515 ArrayExpression: 'ArrayExpression',
4516 BlockStatement: 'BlockStatement',
4517 BinaryExpression: 'BinaryExpression',
4518 BreakStatement: 'BreakStatement',
4519 CallExpression: 'CallExpression',
4520 CatchClause: 'CatchClause',
4521 ConditionalExpression: 'ConditionalExpression',
4522 ContinueStatement: 'ContinueStatement',
4523 DoWhileStatement: 'DoWhileStatement',
4524 DebuggerStatement: 'DebuggerStatement',
4525 EmptyStatement: 'EmptyStatement',
4526 ExpressionStatement: 'ExpressionStatement',
4527 ForStatement: 'ForStatement',
4528 ForInStatement: 'ForInStatement',
4529 FunctionDeclaration: 'FunctionDeclaration',
4530 FunctionExpression: 'FunctionExpression',
4531 Identifier: 'Identifier',
4532 IfStatement: 'IfStatement',
4534 LabeledStatement: 'LabeledStatement',
4535 LogicalExpression: 'LogicalExpression',
4536 MemberExpression: 'MemberExpression',
4537 NewExpression: 'NewExpression',
4538 ObjectExpression: 'ObjectExpression',
4540 Property: 'Property',
4541 ReturnStatement: 'ReturnStatement',
4542 SequenceExpression: 'SequenceExpression',
4543 SwitchStatement: 'SwitchStatement',
4544 SwitchCase: 'SwitchCase',
4545 ThisExpression: 'ThisExpression',
4546 ThrowStatement: 'ThrowStatement',
4547 TryStatement: 'TryStatement',
4548 UnaryExpression: 'UnaryExpression',
4549 UpdateExpression: 'UpdateExpression',
4550 VariableDeclaration: 'VariableDeclaration',
4551 VariableDeclarator: 'VariableDeclarator',
4552 WhileStatement: 'WhileStatement',
4553 WithStatement: 'WithStatement'
4562 // Error messages should be identical to V8.
4564 UnexpectedToken: 'Unexpected token %0',
4565 UnexpectedNumber: 'Unexpected number',
4566 UnexpectedString: 'Unexpected string',
4567 UnexpectedIdentifier: 'Unexpected identifier',
4568 UnexpectedReserved: 'Unexpected reserved word',
4569 UnexpectedEOS: 'Unexpected end of input',
4570 NewlineAfterThrow: 'Illegal newline after throw',
4571 InvalidRegExp: 'Invalid regular expression',
4572 UnterminatedRegExp: 'Invalid regular expression: missing /',
4573 InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
4574 InvalidLHSInForIn: 'Invalid left-hand side in for-in',
4575 MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
4576 NoCatchOrFinally: 'Missing catch or finally after try',
4577 UnknownLabel: 'Undefined label \'%0\'',
4578 Redeclaration: '%0 \'%1\' has already been declared',
4579 IllegalContinue: 'Illegal continue statement',
4580 IllegalBreak: 'Illegal break statement',
4581 IllegalReturn: 'Illegal return statement',
4582 StrictModeWith: 'Strict mode code may not include a with statement',
4583 StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
4584 StrictVarName: 'Variable name may not be eval or arguments in strict mode',
4585 StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
4586 StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
4587 StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
4588 StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
4589 StrictDelete: 'Delete of an unqualified identifier in strict mode.',
4590 StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
4591 AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
4592 AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
4593 StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
4594 StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
4595 StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
4596 StrictReservedWord: 'Use of future reserved word in strict mode'
4599 // See also tools/generate-unicode-regex.py.
4601 NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\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\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\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-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\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-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\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-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\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]'),
4602 NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\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\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\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\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
4605 // Ensure the condition is true, otherwise throw an error.
4606 // This is only to have a better contract semantic, i.e. another safety net
4607 // to catch a logic error. The condition shall be fulfilled in normal case.
4608 // Do NOT use this to enforce a certain condition on any user input.
4610 function assert(condition, message) {
4612 throw new Error('ASSERT: ' + message);
4616 function sliceSource(from, to) {
4617 return source.slice(from, to);
4620 if (typeof 'esprima'[0] === 'undefined') {
4621 sliceSource = function sliceArraySource(from, to) {
4622 return source.slice(from, to).join('');
4626 function isDecimalDigit(ch) {
4627 return '0123456789'.indexOf(ch) >= 0;
4630 function isHexDigit(ch) {
4631 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
4634 function isOctalDigit(ch) {
4635 return '01234567'.indexOf(ch) >= 0;
4641 function isWhiteSpace(ch) {
4642 return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
4643 (ch === '\u000C') || (ch === '\u00A0') ||
4644 (ch.charCodeAt(0) >= 0x1680 &&
4645 '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
4648 // 7.3 Line Terminators
4650 function isLineTerminator(ch) {
4651 return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
4654 // 7.6 Identifier Names and Identifiers
4656 function isIdentifierStart(ch) {
4657 return (ch === '$') || (ch === '_') || (ch === '\\') ||
4658 (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
4659 ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
4662 function isIdentifierPart(ch) {
4663 return (ch === '$') || (ch === '_') || (ch === '\\') ||
4664 (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
4665 ((ch >= '0') && (ch <= '9')) ||
4666 ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
4669 // 7.6.1.2 Future Reserved Words
4671 function isFutureReservedWord(id) {
4674 // Future reserved words.
4687 function isStrictModeReservedWord(id) {
4690 // Strict Mode reserved words.
4706 function isRestrictedWord(id) {
4707 return id === 'eval' || id === 'arguments';
4712 function isKeyword(id) {
4713 var keyword = false;
4714 switch (id.length) {
4716 keyword = (id === 'if') || (id === 'in') || (id === 'do');
4719 keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
4722 keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
4725 keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
4728 keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
4731 keyword = (id === 'default') || (id === 'finally');
4734 keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
4737 keyword = (id === 'instanceof');
4746 // Future reserved words.
4747 // 'const' is specialized as Keyword in V8.
4751 // For compatiblity to SpiderMonkey and ES.next
4757 if (strict && isStrictModeReservedWord(id)) {
4761 return isFutureReservedWord(id);
4766 function skipComment() {
4767 var ch, blockComment, lineComment;
4769 blockComment = false;
4770 lineComment = false;
4772 while (index < length) {
4776 ch = source[index++];
4777 if (isLineTerminator(ch)) {
4778 lineComment = false;
4779 if (ch === '\r' && source[index] === '\n') {
4785 } else if (blockComment) {
4786 if (isLineTerminator(ch)) {
4787 if (ch === '\r' && source[index + 1] === '\n') {
4793 if (index >= length) {
4794 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4797 ch = source[index++];
4798 if (index >= length) {
4799 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4805 blockComment = false;
4809 } else if (ch === '/') {
4810 ch = source[index + 1];
4814 } else if (ch === '*') {
4816 blockComment = true;
4817 if (index >= length) {
4818 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
4823 } else if (isWhiteSpace(ch)) {
4825 } else if (isLineTerminator(ch)) {
4827 if (ch === '\r' && source[index] === '\n') {
4838 function scanHexEscape(prefix) {
4839 var i, len, ch, code = 0;
4841 len = (prefix === 'u') ? 4 : 2;
4842 for (i = 0; i < len; ++i) {
4843 if (index < length && isHexDigit(source[index])) {
4844 ch = source[index++];
4845 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
4850 return String.fromCharCode(code);
4853 function scanIdentifier() {
4854 var ch, start, id, restore;
4857 if (!isIdentifierStart(ch)) {
4864 if (source[index] !== 'u') {
4869 ch = scanHexEscape('u');
4871 if (ch === '\\' || !isIdentifierStart(ch)) {
4880 id = source[index++];
4883 while (index < length) {
4885 if (!isIdentifierPart(ch)) {
4890 if (source[index] !== 'u') {
4895 ch = scanHexEscape('u');
4897 if (ch === '\\' || !isIdentifierPart(ch)) {
4906 id += source[index++];
4910 // There is no keyword or literal with only one character.
4911 // Thus, it must be an identifier.
4912 if (id.length === 1) {
4914 type: Token.Identifier,
4916 lineNumber: lineNumber,
4917 lineStart: lineStart,
4918 range: [start, index]
4922 if (isKeyword(id)) {
4924 type: Token.Keyword,
4926 lineNumber: lineNumber,
4927 lineStart: lineStart,
4928 range: [start, index]
4932 // 7.8.1 Null Literals
4934 if (id === 'null') {
4936 type: Token.NullLiteral,
4938 lineNumber: lineNumber,
4939 lineStart: lineStart,
4940 range: [start, index]
4944 // 7.8.2 Boolean Literals
4946 if (id === 'true' || id === 'false') {
4948 type: Token.BooleanLiteral,
4950 lineNumber: lineNumber,
4951 lineStart: lineStart,
4952 range: [start, index]
4957 type: Token.Identifier,
4959 lineNumber: lineNumber,
4960 lineStart: lineStart,
4961 range: [start, index]
4967 function scanPunctuator() {
4969 ch1 = source[index],
4974 // Check for most common single-character punctuators.
4976 if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
4979 type: Token.Punctuator,
4981 lineNumber: lineNumber,
4982 lineStart: lineStart,
4983 range: [start, index]
4987 if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
4990 type: Token.Punctuator,
4992 lineNumber: lineNumber,
4993 lineStart: lineStart,
4994 range: [start, index]
4998 // Dot (.) can also start a floating-point number, hence the need
4999 // to check the next character.
5001 ch2 = source[index + 1];
5002 if (ch1 === '.' && !isDecimalDigit(ch2)) {
5004 type: Token.Punctuator,
5005 value: source[index++],
5006 lineNumber: lineNumber,
5007 lineStart: lineStart,
5008 range: [start, index]
5012 // Peek more characters.
5014 ch3 = source[index + 2];
5015 ch4 = source[index + 3];
5017 // 4-character punctuator: >>>=
5019 if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
5023 type: Token.Punctuator,
5025 lineNumber: lineNumber,
5026 lineStart: lineStart,
5027 range: [start, index]
5032 // 3-character punctuators: === !== >>> <<= >>=
5034 if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
5037 type: Token.Punctuator,
5039 lineNumber: lineNumber,
5040 lineStart: lineStart,
5041 range: [start, index]
5045 if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
5048 type: Token.Punctuator,
5050 lineNumber: lineNumber,
5051 lineStart: lineStart,
5052 range: [start, index]
5056 if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
5059 type: Token.Punctuator,
5061 lineNumber: lineNumber,
5062 lineStart: lineStart,
5063 range: [start, index]
5067 if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
5070 type: Token.Punctuator,
5072 lineNumber: lineNumber,
5073 lineStart: lineStart,
5074 range: [start, index]
5078 if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
5081 type: Token.Punctuator,
5083 lineNumber: lineNumber,
5084 lineStart: lineStart,
5085 range: [start, index]
5089 // 2-character punctuators: <= >= == != ++ -- << >> && ||
5090 // += -= *= %= &= |= ^= /=
5093 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
5096 type: Token.Punctuator,
5098 lineNumber: lineNumber,
5099 lineStart: lineStart,
5100 range: [start, index]
5105 if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
5106 if ('+-<>&|'.indexOf(ch2) >= 0) {
5109 type: Token.Punctuator,
5111 lineNumber: lineNumber,
5112 lineStart: lineStart,
5113 range: [start, index]
5118 // The remaining 1-character punctuators.
5120 if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
5122 type: Token.Punctuator,
5123 value: source[index++],
5124 lineNumber: lineNumber,
5125 lineStart: lineStart,
5126 range: [start, index]
5131 // 7.8.3 Numeric Literals
5133 function scanNumericLiteral() {
5134 var number, start, ch;
5137 assert(isDecimalDigit(ch) || (ch === '.'),
5138 'Numeric literal must start with a decimal digit or a decimal point');
5143 number = source[index++];
5146 // Hex number starts with '0x'.
5147 // Octal number starts with '0'.
5148 if (number === '0') {
5149 if (ch === 'x' || ch === 'X') {
5150 number += source[index++];
5151 while (index < length) {
5153 if (!isHexDigit(ch)) {
5156 number += source[index++];
5159 if (number.length <= 2) {
5161 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5164 if (index < length) {
5166 if (isIdentifierStart(ch)) {
5167 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5171 type: Token.NumericLiteral,
5172 value: parseInt(number, 16),
5173 lineNumber: lineNumber,
5174 lineStart: lineStart,
5175 range: [start, index]
5177 } else if (isOctalDigit(ch)) {
5178 number += source[index++];
5179 while (index < length) {
5181 if (!isOctalDigit(ch)) {
5184 number += source[index++];
5187 if (index < length) {
5189 if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
5190 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5194 type: Token.NumericLiteral,
5195 value: parseInt(number, 8),
5197 lineNumber: lineNumber,
5198 lineStart: lineStart,
5199 range: [start, index]
5203 // decimal number starts with '0' such as '09' is illegal.
5204 if (isDecimalDigit(ch)) {
5205 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5209 while (index < length) {
5211 if (!isDecimalDigit(ch)) {
5214 number += source[index++];
5219 number += source[index++];
5220 while (index < length) {
5222 if (!isDecimalDigit(ch)) {
5225 number += source[index++];
5229 if (ch === 'e' || ch === 'E') {
5230 number += source[index++];
5233 if (ch === '+' || ch === '-') {
5234 number += source[index++];
5238 if (isDecimalDigit(ch)) {
5239 number += source[index++];
5240 while (index < length) {
5242 if (!isDecimalDigit(ch)) {
5245 number += source[index++];
5248 ch = 'character ' + ch;
5249 if (index >= length) {
5252 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5256 if (index < length) {
5258 if (isIdentifierStart(ch)) {
5259 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5264 type: Token.NumericLiteral,
5265 value: parseFloat(number),
5266 lineNumber: lineNumber,
5267 lineStart: lineStart,
5268 range: [start, index]
5272 // 7.8.4 String Literals
5274 function scanStringLiteral() {
5275 var str = '', quote, start, ch, code, unescaped, restore, octal = false;
5277 quote = source[index];
5278 assert((quote === '\'' || quote === '"'),
5279 'String literal must starts with a quote');
5284 while (index < length) {
5285 ch = source[index++];
5290 } else if (ch === '\\') {
5291 ch = source[index++];
5292 if (!isLineTerminator(ch)) {
5306 unescaped = scanHexEscape(ch);
5325 if (isOctalDigit(ch)) {
5326 code = '01234567'.indexOf(ch);
5328 // \0 is not octal escape sequence
5333 if (index < length && isOctalDigit(source[index])) {
5335 code = code * 8 + '01234567'.indexOf(source[index++]);
5337 // 3 digits are only allowed when string starts
5339 if ('0123'.indexOf(ch) >= 0 &&
5341 isOctalDigit(source[index])) {
5342 code = code * 8 + '01234567'.indexOf(source[index++]);
5345 str += String.fromCharCode(code);
5353 if (ch === '\r' && source[index] === '\n') {
5357 } else if (isLineTerminator(ch)) {
5365 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5369 type: Token.StringLiteral,
5372 lineNumber: lineNumber,
5373 lineStart: lineStart,
5374 range: [start, index]
5378 function scanRegExp() {
5379 var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
5386 assert(ch === '/', 'Regular expression literal must start with a slash');
5387 str = source[index++];
5389 while (index < length) {
5390 ch = source[index++];
5394 classMarker = false;
5398 ch = source[index++];
5400 if (isLineTerminator(ch)) {
5401 throwError({}, Messages.UnterminatedRegExp);
5404 } else if (ch === '/') {
5407 } else if (ch === '[') {
5409 } else if (isLineTerminator(ch)) {
5410 throwError({}, Messages.UnterminatedRegExp);
5416 throwError({}, Messages.UnterminatedRegExp);
5419 // Exclude leading and trailing slash.
5420 pattern = str.substr(1, str.length - 2);
5423 while (index < length) {
5425 if (!isIdentifierPart(ch)) {
5430 if (ch === '\\' && index < length) {
5435 ch = scanHexEscape('u');
5439 for (; restore < index; ++restore) {
5440 str += source[restore];
5457 value = new RegExp(pattern, flags);
5459 throwError({}, Messages.InvalidRegExp);
5465 range: [start, index]
5469 function isIdentifierName(token) {
5470 return token.type === Token.Identifier ||
5471 token.type === Token.Keyword ||
5472 token.type === Token.BooleanLiteral ||
5473 token.type === Token.NullLiteral;
5476 function advance() {
5481 if (index >= length) {
5484 lineNumber: lineNumber,
5485 lineStart: lineStart,
5486 range: [index, index]
5490 token = scanPunctuator();
5491 if (typeof token !== 'undefined') {
5497 if (ch === '\'' || ch === '"') {
5498 return scanStringLiteral();
5501 if (ch === '.' || isDecimalDigit(ch)) {
5502 return scanNumericLiteral();
5505 token = scanIdentifier();
5506 if (typeof token !== 'undefined') {
5510 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5517 index = buffer.range[1];
5518 lineNumber = buffer.lineNumber;
5519 lineStart = buffer.lineStart;
5529 function lookahead() {
5530 var pos, line, start;
5532 if (buffer !== null) {
5547 // Return true if there is a line terminator before the next token.
5549 function peekLineTerminator() {
5550 var pos, line, start, found;
5556 found = lineNumber !== line;
5564 // Throw an exception
5566 function throwError(token, messageFormat) {
5568 args = Array.prototype.slice.call(arguments, 2),
5569 msg = messageFormat.replace(
5571 function (whole, index) {
5572 return args[index] || '';
5576 if (typeof token.lineNumber === 'number') {
5577 error = new Error('Line ' + token.lineNumber + ': ' + msg);
5578 error.index = token.range[0];
5579 error.lineNumber = token.lineNumber;
5580 error.column = token.range[0] - lineStart + 1;
5582 error = new Error('Line ' + lineNumber + ': ' + msg);
5583 error.index = index;
5584 error.lineNumber = lineNumber;
5585 error.column = index - lineStart + 1;
5591 function throwErrorTolerant() {
5593 throwError.apply(null, arguments);
5596 extra.errors.push(e);
5604 // Throw an exception because of the token.
5606 function throwUnexpected(token) {
5607 if (token.type === Token.EOF) {
5608 throwError(token, Messages.UnexpectedEOS);
5611 if (token.type === Token.NumericLiteral) {
5612 throwError(token, Messages.UnexpectedNumber);
5615 if (token.type === Token.StringLiteral) {
5616 throwError(token, Messages.UnexpectedString);
5619 if (token.type === Token.Identifier) {
5620 throwError(token, Messages.UnexpectedIdentifier);
5623 if (token.type === Token.Keyword) {
5624 if (isFutureReservedWord(token.value)) {
5625 throwError(token, Messages.UnexpectedReserved);
5626 } else if (strict && isStrictModeReservedWord(token.value)) {
5627 throwErrorTolerant(token, Messages.StrictReservedWord);
5630 throwError(token, Messages.UnexpectedToken, token.value);
5633 // BooleanLiteral, NullLiteral, or Punctuator.
5634 throwError(token, Messages.UnexpectedToken, token.value);
5637 // Expect the next token to match the specified punctuator.
5638 // If not, an exception will be thrown.
5640 function expect(value) {
5642 if (token.type !== Token.Punctuator || token.value !== value) {
5643 throwUnexpected(token);
5647 // Expect the next token to match the specified keyword.
5648 // If not, an exception will be thrown.
5650 function expectKeyword(keyword) {
5652 if (token.type !== Token.Keyword || token.value !== keyword) {
5653 throwUnexpected(token);
5657 // Return true if the next token matches the specified punctuator.
5659 function match(value) {
5660 var token = lookahead();
5661 return token.type === Token.Punctuator && token.value === value;
5664 // Return true if the next token matches the specified keyword
5666 function matchKeyword(keyword) {
5667 var token = lookahead();
5668 return token.type === Token.Keyword && token.value === keyword;
5671 // Return true if the next token is an assignment operator
5673 function matchAssign() {
5674 var token = lookahead(),
5677 if (token.type !== Token.Punctuator) {
5680 return op === '=' ||
5694 function consumeSemicolon() {
5697 // Catch the very common case first.
5698 if (source[index] === ';') {
5705 if (lineNumber !== line) {
5714 token = lookahead();
5715 if (token.type !== Token.EOF && !match('}')) {
5716 throwUnexpected(token);
5720 // Return true if provided expression is LeftHandSideExpression
5722 function isLeftHandSide(expr) {
5723 return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
5726 // 11.1.4 Array Initialiser
5728 function parseArrayInitialiser() {
5733 while (!match(']')) {
5736 elements.push(null);
5738 elements.push(parseAssignmentExpression());
5749 type: Syntax.ArrayExpression,
5754 // 11.1.5 Object Initialiser
5756 function parsePropertyFunction(param, first) {
5757 var previousStrict, body;
5759 previousStrict = strict;
5760 body = parseFunctionSourceElements();
5761 if (first && strict && isRestrictedWord(param[0].name)) {
5762 throwErrorTolerant(first, Messages.StrictParamName);
5764 strict = previousStrict;
5767 type: Syntax.FunctionExpression,
5778 function parseObjectPropertyKey() {
5781 // Note: This function is called only from parseObjectProperty(), where
5782 // EOF and Punctuator tokens are already filtered out.
5784 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
5785 if (strict && token.octal) {
5786 throwErrorTolerant(token, Messages.StrictOctalLiteral);
5788 return createLiteral(token);
5792 type: Syntax.Identifier,
5797 function parseObjectProperty() {
5798 var token, key, id, param;
5800 token = lookahead();
5802 if (token.type === Token.Identifier) {
5804 id = parseObjectPropertyKey();
5806 // Property Assignment: Getter and Setter.
5808 if (token.value === 'get' && !match(':')) {
5809 key = parseObjectPropertyKey();
5813 type: Syntax.Property,
5815 value: parsePropertyFunction([]),
5818 } else if (token.value === 'set' && !match(':')) {
5819 key = parseObjectPropertyKey();
5821 token = lookahead();
5822 if (token.type !== Token.Identifier) {
5824 throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
5826 type: Syntax.Property,
5828 value: parsePropertyFunction([]),
5832 param = [ parseVariableIdentifier() ];
5835 type: Syntax.Property,
5837 value: parsePropertyFunction(param, token),
5844 type: Syntax.Property,
5846 value: parseAssignmentExpression(),
5850 } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
5851 throwUnexpected(token);
5853 key = parseObjectPropertyKey();
5856 type: Syntax.Property,
5858 value: parseAssignmentExpression(),
5864 function parseObjectInitialiser() {
5865 var properties = [], property, name, kind, map = {}, toString = String;
5869 while (!match('}')) {
5870 property = parseObjectProperty();
5872 if (property.key.type === Syntax.Identifier) {
5873 name = property.key.name;
5875 name = toString(property.key.value);
5877 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
5878 if (Object.prototype.hasOwnProperty.call(map, name)) {
5879 if (map[name] === PropertyKind.Data) {
5880 if (strict && kind === PropertyKind.Data) {
5881 throwErrorTolerant({}, Messages.StrictDuplicateProperty);
5882 } else if (kind !== PropertyKind.Data) {
5883 throwErrorTolerant({}, Messages.AccessorDataProperty);
5886 if (kind === PropertyKind.Data) {
5887 throwErrorTolerant({}, Messages.AccessorDataProperty);
5888 } else if (map[name] & kind) {
5889 throwErrorTolerant({}, Messages.AccessorGetSet);
5897 properties.push(property);
5907 type: Syntax.ObjectExpression,
5908 properties: properties
5912 // 11.1.6 The Grouping Operator
5914 function parseGroupExpression() {
5919 expr = parseExpression();
5927 // 11.1 Primary Expressions
5929 function parsePrimaryExpression() {
5930 var token = lookahead(),
5933 if (type === Token.Identifier) {
5935 type: Syntax.Identifier,
5940 if (type === Token.StringLiteral || type === Token.NumericLiteral) {
5941 if (strict && token.octal) {
5942 throwErrorTolerant(token, Messages.StrictOctalLiteral);
5944 return createLiteral(lex());
5947 if (type === Token.Keyword) {
5948 if (matchKeyword('this')) {
5951 type: Syntax.ThisExpression
5955 if (matchKeyword('function')) {
5956 return parseFunctionExpression();
5960 if (type === Token.BooleanLiteral) {
5962 token.value = (token.value === 'true');
5963 return createLiteral(token);
5966 if (type === Token.NullLiteral) {
5969 return createLiteral(token);
5973 return parseArrayInitialiser();
5977 return parseObjectInitialiser();
5981 return parseGroupExpression();
5984 if (match('/') || match('/=')) {
5985 return createLiteral(scanRegExp());
5988 return throwUnexpected(lex());
5991 // 11.2 Left-Hand-Side Expressions
5993 function parseArguments() {
5999 while (index < length) {
6000 args.push(parseAssignmentExpression());
6013 function parseNonComputedProperty() {
6016 if (!isIdentifierName(token)) {
6017 throwUnexpected(token);
6021 type: Syntax.Identifier,
6026 function parseNonComputedMember() {
6029 return parseNonComputedProperty();
6032 function parseComputedMember() {
6037 expr = parseExpression();
6044 function parseNewExpression() {
6047 expectKeyword('new');
6050 type: Syntax.NewExpression,
6051 callee: parseLeftHandSideExpression(),
6056 expr['arguments'] = parseArguments();
6062 function parseLeftHandSideExpressionAllowCall() {
6065 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
6067 while (match('.') || match('[') || match('(')) {
6070 type: Syntax.CallExpression,
6072 'arguments': parseArguments()
6074 } else if (match('[')) {
6076 type: Syntax.MemberExpression,
6079 property: parseComputedMember()
6083 type: Syntax.MemberExpression,
6086 property: parseNonComputedMember()
6095 function parseLeftHandSideExpression() {
6098 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
6100 while (match('.') || match('[')) {
6103 type: Syntax.MemberExpression,
6106 property: parseComputedMember()
6110 type: Syntax.MemberExpression,
6113 property: parseNonComputedMember()
6121 // 11.3 Postfix Expressions
6123 function parsePostfixExpression() {
6124 var expr = parseLeftHandSideExpressionAllowCall(), token;
6126 token = lookahead();
6127 if (token.type !== Token.Punctuator) {
6131 if ((match('++') || match('--')) && !peekLineTerminator()) {
6133 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
6134 throwErrorTolerant({}, Messages.StrictLHSPostfix);
6137 if (!isLeftHandSide(expr)) {
6138 throwError({}, Messages.InvalidLHSInAssignment);
6142 type: Syntax.UpdateExpression,
6143 operator: lex().value,
6152 // 11.4 Unary Operators
6154 function parseUnaryExpression() {
6157 token = lookahead();
6158 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
6159 return parsePostfixExpression();
6162 if (match('++') || match('--')) {
6164 expr = parseUnaryExpression();
6166 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
6167 throwErrorTolerant({}, Messages.StrictLHSPrefix);
6170 if (!isLeftHandSide(expr)) {
6171 throwError({}, Messages.InvalidLHSInAssignment);
6175 type: Syntax.UpdateExpression,
6176 operator: token.value,
6183 if (match('+') || match('-') || match('~') || match('!')) {
6185 type: Syntax.UnaryExpression,
6186 operator: lex().value,
6187 argument: parseUnaryExpression(),
6193 if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
6195 type: Syntax.UnaryExpression,
6196 operator: lex().value,
6197 argument: parseUnaryExpression(),
6200 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
6201 throwErrorTolerant({}, Messages.StrictDelete);
6206 return parsePostfixExpression();
6209 // 11.5 Multiplicative Operators
6211 function parseMultiplicativeExpression() {
6212 var expr = parseUnaryExpression();
6214 while (match('*') || match('/') || match('%')) {
6216 type: Syntax.BinaryExpression,
6217 operator: lex().value,
6219 right: parseUnaryExpression()
6226 // 11.6 Additive Operators
6228 function parseAdditiveExpression() {
6229 var expr = parseMultiplicativeExpression();
6231 while (match('+') || match('-')) {
6233 type: Syntax.BinaryExpression,
6234 operator: lex().value,
6236 right: parseMultiplicativeExpression()
6243 // 11.7 Bitwise Shift Operators
6245 function parseShiftExpression() {
6246 var expr = parseAdditiveExpression();
6248 while (match('<<') || match('>>') || match('>>>')) {
6250 type: Syntax.BinaryExpression,
6251 operator: lex().value,
6253 right: parseAdditiveExpression()
6259 // 11.8 Relational Operators
6261 function parseRelationalExpression() {
6262 var expr, previousAllowIn;
6264 previousAllowIn = state.allowIn;
6265 state.allowIn = true;
6267 expr = parseShiftExpression();
6269 while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
6271 type: Syntax.BinaryExpression,
6272 operator: lex().value,
6274 right: parseShiftExpression()
6278 state.allowIn = previousAllowIn;
6282 // 11.9 Equality Operators
6284 function parseEqualityExpression() {
6285 var expr = parseRelationalExpression();
6287 while (match('==') || match('!=') || match('===') || match('!==')) {
6289 type: Syntax.BinaryExpression,
6290 operator: lex().value,
6292 right: parseRelationalExpression()
6299 // 11.10 Binary Bitwise Operators
6301 function parseBitwiseANDExpression() {
6302 var expr = parseEqualityExpression();
6304 while (match('&')) {
6307 type: Syntax.BinaryExpression,
6310 right: parseEqualityExpression()
6317 function parseBitwiseXORExpression() {
6318 var expr = parseBitwiseANDExpression();
6320 while (match('^')) {
6323 type: Syntax.BinaryExpression,
6326 right: parseBitwiseANDExpression()
6333 function parseBitwiseORExpression() {
6334 var expr = parseBitwiseXORExpression();
6336 while (match('|')) {
6339 type: Syntax.BinaryExpression,
6342 right: parseBitwiseXORExpression()
6349 // 11.11 Binary Logical Operators
6351 function parseLogicalANDExpression() {
6352 var expr = parseBitwiseORExpression();
6354 while (match('&&')) {
6357 type: Syntax.LogicalExpression,
6360 right: parseBitwiseORExpression()
6367 function parseLogicalORExpression() {
6368 var expr = parseLogicalANDExpression();
6370 while (match('||')) {
6373 type: Syntax.LogicalExpression,
6376 right: parseLogicalANDExpression()
6383 // 11.12 Conditional Operator
6385 function parseConditionalExpression() {
6386 var expr, previousAllowIn, consequent;
6388 expr = parseLogicalORExpression();
6392 previousAllowIn = state.allowIn;
6393 state.allowIn = true;
6394 consequent = parseAssignmentExpression();
6395 state.allowIn = previousAllowIn;
6399 type: Syntax.ConditionalExpression,
6401 consequent: consequent,
6402 alternate: parseAssignmentExpression()
6409 // 11.13 Assignment Operators
6411 function parseAssignmentExpression() {
6414 token = lookahead();
6415 expr = parseConditionalExpression();
6417 if (matchAssign()) {
6418 // LeftHandSideExpression
6419 if (!isLeftHandSide(expr)) {
6420 throwError({}, Messages.InvalidLHSInAssignment);
6424 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
6425 throwErrorTolerant(token, Messages.StrictLHSAssignment);
6429 type: Syntax.AssignmentExpression,
6430 operator: lex().value,
6432 right: parseAssignmentExpression()
6439 // 11.14 Comma Operator
6441 function parseExpression() {
6442 var expr = parseAssignmentExpression();
6446 type: Syntax.SequenceExpression,
6447 expressions: [ expr ]
6450 while (index < length) {
6455 expr.expressions.push(parseAssignmentExpression());
6464 function parseStatementList() {
6468 while (index < length) {
6472 statement = parseSourceElement();
6473 if (typeof statement === 'undefined') {
6476 list.push(statement);
6482 function parseBlock() {
6487 block = parseStatementList();
6492 type: Syntax.BlockStatement,
6497 // 12.2 Variable Statement
6499 function parseVariableIdentifier() {
6502 if (token.type !== Token.Identifier) {
6503 throwUnexpected(token);
6507 type: Syntax.Identifier,
6512 function parseVariableDeclaration(kind) {
6513 var id = parseVariableIdentifier(),
6517 if (strict && isRestrictedWord(id.name)) {
6518 throwErrorTolerant({}, Messages.StrictVarName);
6521 if (kind === 'const') {
6523 init = parseAssignmentExpression();
6524 } else if (match('=')) {
6526 init = parseAssignmentExpression();
6530 type: Syntax.VariableDeclarator,
6536 function parseVariableDeclarationList(kind) {
6540 list.push(parseVariableDeclaration(kind));
6545 } while (index < length);
6550 function parseVariableStatement() {
6553 expectKeyword('var');
6555 declarations = parseVariableDeclarationList();
6560 type: Syntax.VariableDeclaration,
6561 declarations: declarations,
6566 // kind may be `const` or `let`
6567 // Both are experimental and not in the specification yet.
6568 // see http://wiki.ecmascript.org/doku.php?id=harmony:const
6569 // and http://wiki.ecmascript.org/doku.php?id=harmony:let
6570 function parseConstLetDeclaration(kind) {
6573 expectKeyword(kind);
6575 declarations = parseVariableDeclarationList(kind);
6580 type: Syntax.VariableDeclaration,
6581 declarations: declarations,
6586 // 12.3 Empty Statement
6588 function parseEmptyStatement() {
6592 type: Syntax.EmptyStatement
6596 // 12.4 Expression Statement
6598 function parseExpressionStatement() {
6599 var expr = parseExpression();
6604 type: Syntax.ExpressionStatement,
6609 // 12.5 If statement
6611 function parseIfStatement() {
6612 var test, consequent, alternate;
6614 expectKeyword('if');
6618 test = parseExpression();
6622 consequent = parseStatement();
6624 if (matchKeyword('else')) {
6626 alternate = parseStatement();
6632 type: Syntax.IfStatement,
6634 consequent: consequent,
6635 alternate: alternate
6639 // 12.6 Iteration Statements
6641 function parseDoWhileStatement() {
6642 var body, test, oldInIteration;
6644 expectKeyword('do');
6646 oldInIteration = state.inIteration;
6647 state.inIteration = true;
6649 body = parseStatement();
6651 state.inIteration = oldInIteration;
6653 expectKeyword('while');
6657 test = parseExpression();
6666 type: Syntax.DoWhileStatement,
6672 function parseWhileStatement() {
6673 var test, body, oldInIteration;
6675 expectKeyword('while');
6679 test = parseExpression();
6683 oldInIteration = state.inIteration;
6684 state.inIteration = true;
6686 body = parseStatement();
6688 state.inIteration = oldInIteration;
6691 type: Syntax.WhileStatement,
6697 function parseForVariableDeclaration() {
6701 type: Syntax.VariableDeclaration,
6702 declarations: parseVariableDeclarationList(),
6707 function parseForStatement() {
6708 var init, test, update, left, right, body, oldInIteration;
6710 init = test = update = null;
6712 expectKeyword('for');
6719 if (matchKeyword('var') || matchKeyword('let')) {
6720 state.allowIn = false;
6721 init = parseForVariableDeclaration();
6722 state.allowIn = true;
6724 if (init.declarations.length === 1 && matchKeyword('in')) {
6727 right = parseExpression();
6731 state.allowIn = false;
6732 init = parseExpression();
6733 state.allowIn = true;
6735 if (matchKeyword('in')) {
6736 // LeftHandSideExpression
6737 if (!isLeftHandSide(init)) {
6738 throwError({}, Messages.InvalidLHSInForIn);
6743 right = parseExpression();
6748 if (typeof left === 'undefined') {
6753 if (typeof left === 'undefined') {
6756 test = parseExpression();
6761 update = parseExpression();
6767 oldInIteration = state.inIteration;
6768 state.inIteration = true;
6770 body = parseStatement();
6772 state.inIteration = oldInIteration;
6774 if (typeof left === 'undefined') {
6776 type: Syntax.ForStatement,
6785 type: Syntax.ForInStatement,
6793 // 12.7 The continue statement
6795 function parseContinueStatement() {
6796 var token, label = null;
6798 expectKeyword('continue');
6800 // Optimize the most common form: 'continue;'.
6801 if (source[index] === ';') {
6804 if (!state.inIteration) {
6805 throwError({}, Messages.IllegalContinue);
6809 type: Syntax.ContinueStatement,
6814 if (peekLineTerminator()) {
6815 if (!state.inIteration) {
6816 throwError({}, Messages.IllegalContinue);
6820 type: Syntax.ContinueStatement,
6825 token = lookahead();
6826 if (token.type === Token.Identifier) {
6827 label = parseVariableIdentifier();
6829 if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
6830 throwError({}, Messages.UnknownLabel, label.name);
6836 if (label === null && !state.inIteration) {
6837 throwError({}, Messages.IllegalContinue);
6841 type: Syntax.ContinueStatement,
6846 // 12.8 The break statement
6848 function parseBreakStatement() {
6849 var token, label = null;
6851 expectKeyword('break');
6853 // Optimize the most common form: 'break;'.
6854 if (source[index] === ';') {
6857 if (!(state.inIteration || state.inSwitch)) {
6858 throwError({}, Messages.IllegalBreak);
6862 type: Syntax.BreakStatement,
6867 if (peekLineTerminator()) {
6868 if (!(state.inIteration || state.inSwitch)) {
6869 throwError({}, Messages.IllegalBreak);
6873 type: Syntax.BreakStatement,
6878 token = lookahead();
6879 if (token.type === Token.Identifier) {
6880 label = parseVariableIdentifier();
6882 if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
6883 throwError({}, Messages.UnknownLabel, label.name);
6889 if (label === null && !(state.inIteration || state.inSwitch)) {
6890 throwError({}, Messages.IllegalBreak);
6894 type: Syntax.BreakStatement,
6899 // 12.9 The return statement
6901 function parseReturnStatement() {
6902 var token, argument = null;
6904 expectKeyword('return');
6906 if (!state.inFunctionBody) {
6907 throwErrorTolerant({}, Messages.IllegalReturn);
6910 // 'return' followed by a space and an identifier is very common.
6911 if (source[index] === ' ') {
6912 if (isIdentifierStart(source[index + 1])) {
6913 argument = parseExpression();
6916 type: Syntax.ReturnStatement,
6922 if (peekLineTerminator()) {
6924 type: Syntax.ReturnStatement,
6930 token = lookahead();
6931 if (!match('}') && token.type !== Token.EOF) {
6932 argument = parseExpression();
6939 type: Syntax.ReturnStatement,
6944 // 12.10 The with statement
6946 function parseWithStatement() {
6950 throwErrorTolerant({}, Messages.StrictModeWith);
6953 expectKeyword('with');
6957 object = parseExpression();
6961 body = parseStatement();
6964 type: Syntax.WithStatement,
6970 // 12.10 The swith statement
6972 function parseSwitchCase() {
6977 if (matchKeyword('default')) {
6981 expectKeyword('case');
6982 test = parseExpression();
6986 while (index < length) {
6987 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
6990 statement = parseStatement();
6991 if (typeof statement === 'undefined') {
6994 consequent.push(statement);
6998 type: Syntax.SwitchCase,
7000 consequent: consequent
7004 function parseSwitchStatement() {
7005 var discriminant, cases, clause, oldInSwitch, defaultFound;
7007 expectKeyword('switch');
7011 discriminant = parseExpression();
7020 type: Syntax.SwitchStatement,
7021 discriminant: discriminant
7027 oldInSwitch = state.inSwitch;
7028 state.inSwitch = true;
7029 defaultFound = false;
7031 while (index < length) {
7035 clause = parseSwitchCase();
7036 if (clause.test === null) {
7038 throwError({}, Messages.MultipleDefaultsInSwitch);
7040 defaultFound = true;
7045 state.inSwitch = oldInSwitch;
7050 type: Syntax.SwitchStatement,
7051 discriminant: discriminant,
7056 // 12.13 The throw statement
7058 function parseThrowStatement() {
7061 expectKeyword('throw');
7063 if (peekLineTerminator()) {
7064 throwError({}, Messages.NewlineAfterThrow);
7067 argument = parseExpression();
7072 type: Syntax.ThrowStatement,
7077 // 12.14 The try statement
7079 function parseCatchClause() {
7082 expectKeyword('catch');
7086 throwUnexpected(lookahead());
7089 param = parseVariableIdentifier();
7091 if (strict && isRestrictedWord(param.name)) {
7092 throwErrorTolerant({}, Messages.StrictCatchVariable);
7098 type: Syntax.CatchClause,
7104 function parseTryStatement() {
7105 var block, handlers = [], finalizer = null;
7107 expectKeyword('try');
7109 block = parseBlock();
7111 if (matchKeyword('catch')) {
7112 handlers.push(parseCatchClause());
7115 if (matchKeyword('finally')) {
7117 finalizer = parseBlock();
7120 if (handlers.length === 0 && !finalizer) {
7121 throwError({}, Messages.NoCatchOrFinally);
7125 type: Syntax.TryStatement,
7127 guardedHandlers: [],
7129 finalizer: finalizer
7133 // 12.15 The debugger statement
7135 function parseDebuggerStatement() {
7136 expectKeyword('debugger');
7141 type: Syntax.DebuggerStatement
7147 function parseStatement() {
7148 var token = lookahead(),
7152 if (token.type === Token.EOF) {
7153 throwUnexpected(token);
7156 if (token.type === Token.Punctuator) {
7157 switch (token.value) {
7159 return parseEmptyStatement();
7161 return parseBlock();
7163 return parseExpressionStatement();
7169 if (token.type === Token.Keyword) {
7170 switch (token.value) {
7172 return parseBreakStatement();
7174 return parseContinueStatement();
7176 return parseDebuggerStatement();
7178 return parseDoWhileStatement();
7180 return parseForStatement();
7182 return parseFunctionDeclaration();
7184 return parseIfStatement();
7186 return parseReturnStatement();
7188 return parseSwitchStatement();
7190 return parseThrowStatement();
7192 return parseTryStatement();
7194 return parseVariableStatement();
7196 return parseWhileStatement();
7198 return parseWithStatement();
7204 expr = parseExpression();
7206 // 12.12 Labelled Statements
7207 if ((expr.type === Syntax.Identifier) && match(':')) {
7210 if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
7211 throwError({}, Messages.Redeclaration, 'Label', expr.name);
7214 state.labelSet[expr.name] = true;
7215 labeledBody = parseStatement();
7216 delete state.labelSet[expr.name];
7219 type: Syntax.LabeledStatement,
7228 type: Syntax.ExpressionStatement,
7233 // 13 Function Definition
7235 function parseFunctionSourceElements() {
7236 var sourceElement, sourceElements = [], token, directive, firstRestricted,
7237 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
7241 while (index < length) {
7242 token = lookahead();
7243 if (token.type !== Token.StringLiteral) {
7247 sourceElement = parseSourceElement();
7248 sourceElements.push(sourceElement);
7249 if (sourceElement.expression.type !== Syntax.Literal) {
7250 // this is not directive
7253 directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
7254 if (directive === 'use strict') {
7256 if (firstRestricted) {
7257 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
7260 if (!firstRestricted && token.octal) {
7261 firstRestricted = token;
7266 oldLabelSet = state.labelSet;
7267 oldInIteration = state.inIteration;
7268 oldInSwitch = state.inSwitch;
7269 oldInFunctionBody = state.inFunctionBody;
7271 state.labelSet = {};
7272 state.inIteration = false;
7273 state.inSwitch = false;
7274 state.inFunctionBody = true;
7276 while (index < length) {
7280 sourceElement = parseSourceElement();
7281 if (typeof sourceElement === 'undefined') {
7284 sourceElements.push(sourceElement);
7289 state.labelSet = oldLabelSet;
7290 state.inIteration = oldInIteration;
7291 state.inSwitch = oldInSwitch;
7292 state.inFunctionBody = oldInFunctionBody;
7295 type: Syntax.BlockStatement,
7296 body: sourceElements
7300 function parseFunctionDeclaration() {
7301 var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet;
7303 expectKeyword('function');
7304 token = lookahead();
7305 id = parseVariableIdentifier();
7307 if (isRestrictedWord(token.value)) {
7308 throwErrorTolerant(token, Messages.StrictFunctionName);
7311 if (isRestrictedWord(token.value)) {
7312 firstRestricted = token;
7313 message = Messages.StrictFunctionName;
7314 } else if (isStrictModeReservedWord(token.value)) {
7315 firstRestricted = token;
7316 message = Messages.StrictReservedWord;
7324 while (index < length) {
7325 token = lookahead();
7326 param = parseVariableIdentifier();
7328 if (isRestrictedWord(token.value)) {
7330 message = Messages.StrictParamName;
7332 if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
7334 message = Messages.StrictParamDupe;
7336 } else if (!firstRestricted) {
7337 if (isRestrictedWord(token.value)) {
7338 firstRestricted = token;
7339 message = Messages.StrictParamName;
7340 } else if (isStrictModeReservedWord(token.value)) {
7341 firstRestricted = token;
7342 message = Messages.StrictReservedWord;
7343 } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
7344 firstRestricted = token;
7345 message = Messages.StrictParamDupe;
7349 paramSet[param.name] = true;
7359 previousStrict = strict;
7360 body = parseFunctionSourceElements();
7361 if (strict && firstRestricted) {
7362 throwError(firstRestricted, message);
7364 if (strict && stricted) {
7365 throwErrorTolerant(stricted, message);
7367 strict = previousStrict;
7370 type: Syntax.FunctionDeclaration,
7381 function parseFunctionExpression() {
7382 var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet;
7384 expectKeyword('function');
7387 token = lookahead();
7388 id = parseVariableIdentifier();
7390 if (isRestrictedWord(token.value)) {
7391 throwErrorTolerant(token, Messages.StrictFunctionName);
7394 if (isRestrictedWord(token.value)) {
7395 firstRestricted = token;
7396 message = Messages.StrictFunctionName;
7397 } else if (isStrictModeReservedWord(token.value)) {
7398 firstRestricted = token;
7399 message = Messages.StrictReservedWord;
7408 while (index < length) {
7409 token = lookahead();
7410 param = parseVariableIdentifier();
7412 if (isRestrictedWord(token.value)) {
7414 message = Messages.StrictParamName;
7416 if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
7418 message = Messages.StrictParamDupe;
7420 } else if (!firstRestricted) {
7421 if (isRestrictedWord(token.value)) {
7422 firstRestricted = token;
7423 message = Messages.StrictParamName;
7424 } else if (isStrictModeReservedWord(token.value)) {
7425 firstRestricted = token;
7426 message = Messages.StrictReservedWord;
7427 } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
7428 firstRestricted = token;
7429 message = Messages.StrictParamDupe;
7433 paramSet[param.name] = true;
7443 previousStrict = strict;
7444 body = parseFunctionSourceElements();
7445 if (strict && firstRestricted) {
7446 throwError(firstRestricted, message);
7448 if (strict && stricted) {
7449 throwErrorTolerant(stricted, message);
7451 strict = previousStrict;
7454 type: Syntax.FunctionExpression,
7467 function parseSourceElement() {
7468 var token = lookahead();
7470 if (token.type === Token.Keyword) {
7471 switch (token.value) {
7474 return parseConstLetDeclaration(token.value);
7476 return parseFunctionDeclaration();
7478 return parseStatement();
7482 if (token.type !== Token.EOF) {
7483 return parseStatement();
7487 function parseSourceElements() {
7488 var sourceElement, sourceElements = [], token, directive, firstRestricted;
7490 while (index < length) {
7491 token = lookahead();
7492 if (token.type !== Token.StringLiteral) {
7496 sourceElement = parseSourceElement();
7497 sourceElements.push(sourceElement);
7498 if (sourceElement.expression.type !== Syntax.Literal) {
7499 // this is not directive
7502 directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
7503 if (directive === 'use strict') {
7505 if (firstRestricted) {
7506 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
7509 if (!firstRestricted && token.octal) {
7510 firstRestricted = token;
7515 while (index < length) {
7516 sourceElement = parseSourceElement();
7517 if (typeof sourceElement === 'undefined') {
7520 sourceElements.push(sourceElement);
7522 return sourceElements;
7525 function parseProgram() {
7529 type: Syntax.Program,
7530 body: parseSourceElements()
7535 // The following functions are needed only when the option to preserve
7536 // the comments is active.
7538 function addComment(type, value, start, end, loc) {
7539 assert(typeof start === 'number', 'Comment must have valid position');
7541 // Because the way the actual token is scanned, often the comments
7542 // (if any) are skipped twice during the lexical analysis.
7543 // Thus, we need to skip adding a comment if the comment array already
7545 if (extra.comments.length > 0) {
7546 if (extra.comments[extra.comments.length - 1].range[1] > start) {
7551 extra.comments.push({
7554 range: [start, end],
7559 function scanComment() {
7560 var comment, ch, loc, start, blockComment, lineComment;
7563 blockComment = false;
7564 lineComment = false;
7566 while (index < length) {
7570 ch = source[index++];
7571 if (isLineTerminator(ch)) {
7574 column: index - lineStart - 1
7576 lineComment = false;
7577 addComment('Line', comment, start, index - 1, loc);
7578 if (ch === '\r' && source[index] === '\n') {
7584 } else if (index >= length) {
7585 lineComment = false;
7589 column: length - lineStart
7591 addComment('Line', comment, start, length, loc);
7595 } else if (blockComment) {
7596 if (isLineTerminator(ch)) {
7597 if (ch === '\r' && source[index + 1] === '\n') {
7606 if (index >= length) {
7607 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
7610 ch = source[index++];
7611 if (index >= length) {
7612 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
7618 comment = comment.substr(0, comment.length - 1);
7619 blockComment = false;
7623 column: index - lineStart
7625 addComment('Block', comment, start, index, loc);
7630 } else if (ch === '/') {
7631 ch = source[index + 1];
7636 column: index - lineStart
7642 if (index >= length) {
7645 column: index - lineStart
7647 lineComment = false;
7648 addComment('Line', comment, start, index, loc);
7650 } else if (ch === '*') {
7653 blockComment = true;
7657 column: index - lineStart - 2
7660 if (index >= length) {
7661 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
7666 } else if (isWhiteSpace(ch)) {
7668 } else if (isLineTerminator(ch)) {
7670 if (ch === '\r' && source[index] === '\n') {
7681 function filterCommentLocation() {
7682 var i, entry, comment, comments = [];
7684 for (i = 0; i < extra.comments.length; ++i) {
7685 entry = extra.comments[i];
7691 comment.range = entry.range;
7694 comment.loc = entry.loc;
7696 comments.push(comment);
7699 extra.comments = comments;
7702 function collectToken() {
7703 var start, loc, token, range, value;
7710 column: index - lineStart
7714 token = extra.advance();
7717 column: index - lineStart
7720 if (token.type !== Token.EOF) {
7721 range = [token.range[0], token.range[1]];
7722 value = sliceSource(token.range[0], token.range[1]);
7724 type: TokenName[token.type],
7734 function collectRegex() {
7735 var pos, loc, regex, token;
7743 column: index - lineStart
7747 regex = extra.scanRegExp();
7750 column: index - lineStart
7753 // Pop the previous token, which is likely '/' or '/='
7754 if (extra.tokens.length > 0) {
7755 token = extra.tokens[extra.tokens.length - 1];
7756 if (token.range[0] === pos && token.type === 'Punctuator') {
7757 if (token.value === '/' || token.value === '/=') {
7764 type: 'RegularExpression',
7765 value: regex.literal,
7766 range: [pos, index],
7773 function filterTokenLocation() {
7774 var i, entry, token, tokens = [];
7776 for (i = 0; i < extra.tokens.length; ++i) {
7777 entry = extra.tokens[i];
7783 token.range = entry.range;
7786 token.loc = entry.loc;
7791 extra.tokens = tokens;
7794 function createLiteral(token) {
7796 type: Syntax.Literal,
7801 function createRawLiteral(token) {
7803 type: Syntax.Literal,
7805 raw: sliceSource(token.range[0], token.range[1])
7809 function createLocationMarker() {
7812 marker.range = [index, index];
7816 column: index - lineStart
7820 column: index - lineStart
7824 marker.end = function () {
7825 this.range[1] = index;
7826 this.loc.end.line = lineNumber;
7827 this.loc.end.column = index - lineStart;
7830 marker.applyGroup = function (node) {
7832 node.groupRange = [this.range[0], this.range[1]];
7837 line: this.loc.start.line,
7838 column: this.loc.start.column
7841 line: this.loc.end.line,
7842 column: this.loc.end.column
7848 marker.apply = function (node) {
7850 node.range = [this.range[0], this.range[1]];
7855 line: this.loc.start.line,
7856 column: this.loc.start.column
7859 line: this.loc.end.line,
7860 column: this.loc.end.column
7869 function trackGroupExpression() {
7873 marker = createLocationMarker();
7876 expr = parseExpression();
7881 marker.applyGroup(expr);
7886 function trackLeftHandSideExpression() {
7890 marker = createLocationMarker();
7892 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
7894 while (match('.') || match('[')) {
7897 type: Syntax.MemberExpression,
7900 property: parseComputedMember()
7906 type: Syntax.MemberExpression,
7909 property: parseNonComputedMember()
7919 function trackLeftHandSideExpressionAllowCall() {
7923 marker = createLocationMarker();
7925 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
7927 while (match('.') || match('[') || match('(')) {
7930 type: Syntax.CallExpression,
7932 'arguments': parseArguments()
7936 } else if (match('[')) {
7938 type: Syntax.MemberExpression,
7941 property: parseComputedMember()
7947 type: Syntax.MemberExpression,
7950 property: parseNonComputedMember()
7960 function filterGroup(node) {
7963 n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {};
7965 if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') {
7967 if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) {
7970 n[i] = filterGroup(entry);
7977 function wrapTrackingFunction(range, loc) {
7979 return function (parseFunction) {
7981 function isBinary(node) {
7982 return node.type === Syntax.LogicalExpression ||
7983 node.type === Syntax.BinaryExpression;
7986 function visit(node) {
7989 if (isBinary(node.left)) {
7992 if (isBinary(node.right)) {
7997 if (node.left.groupRange || node.right.groupRange) {
7998 start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0];
7999 end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1];
8000 node.range = [start, end];
8001 } else if (typeof node.range === 'undefined') {
8002 start = node.left.range[0];
8003 end = node.right.range[1];
8004 node.range = [start, end];
8008 if (node.left.groupLoc || node.right.groupLoc) {
8009 start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start;
8010 end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end;
8015 } else if (typeof node.loc === 'undefined') {
8017 start: node.left.loc.start,
8018 end: node.right.loc.end
8024 return function () {
8029 marker = createLocationMarker();
8030 node = parseFunction.apply(null, arguments);
8033 if (range && typeof node.range === 'undefined') {
8037 if (loc && typeof node.loc === 'undefined') {
8041 if (isBinary(node)) {
8054 if (extra.comments) {
8055 extra.skipComment = skipComment;
8056 skipComment = scanComment;
8060 extra.createLiteral = createLiteral;
8061 createLiteral = createRawLiteral;
8064 if (extra.range || extra.loc) {
8066 extra.parseGroupExpression = parseGroupExpression;
8067 extra.parseLeftHandSideExpression = parseLeftHandSideExpression;
8068 extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall;
8069 parseGroupExpression = trackGroupExpression;
8070 parseLeftHandSideExpression = trackLeftHandSideExpression;
8071 parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall;
8073 wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
8075 extra.parseAdditiveExpression = parseAdditiveExpression;
8076 extra.parseAssignmentExpression = parseAssignmentExpression;
8077 extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
8078 extra.parseBitwiseORExpression = parseBitwiseORExpression;
8079 extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
8080 extra.parseBlock = parseBlock;
8081 extra.parseFunctionSourceElements = parseFunctionSourceElements;
8082 extra.parseCatchClause = parseCatchClause;
8083 extra.parseComputedMember = parseComputedMember;
8084 extra.parseConditionalExpression = parseConditionalExpression;
8085 extra.parseConstLetDeclaration = parseConstLetDeclaration;
8086 extra.parseEqualityExpression = parseEqualityExpression;
8087 extra.parseExpression = parseExpression;
8088 extra.parseForVariableDeclaration = parseForVariableDeclaration;
8089 extra.parseFunctionDeclaration = parseFunctionDeclaration;
8090 extra.parseFunctionExpression = parseFunctionExpression;
8091 extra.parseLogicalANDExpression = parseLogicalANDExpression;
8092 extra.parseLogicalORExpression = parseLogicalORExpression;
8093 extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
8094 extra.parseNewExpression = parseNewExpression;
8095 extra.parseNonComputedProperty = parseNonComputedProperty;
8096 extra.parseObjectProperty = parseObjectProperty;
8097 extra.parseObjectPropertyKey = parseObjectPropertyKey;
8098 extra.parsePostfixExpression = parsePostfixExpression;
8099 extra.parsePrimaryExpression = parsePrimaryExpression;
8100 extra.parseProgram = parseProgram;
8101 extra.parsePropertyFunction = parsePropertyFunction;
8102 extra.parseRelationalExpression = parseRelationalExpression;
8103 extra.parseStatement = parseStatement;
8104 extra.parseShiftExpression = parseShiftExpression;
8105 extra.parseSwitchCase = parseSwitchCase;
8106 extra.parseUnaryExpression = parseUnaryExpression;
8107 extra.parseVariableDeclaration = parseVariableDeclaration;
8108 extra.parseVariableIdentifier = parseVariableIdentifier;
8110 parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
8111 parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
8112 parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
8113 parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
8114 parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
8115 parseBlock = wrapTracking(extra.parseBlock);
8116 parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
8117 parseCatchClause = wrapTracking(extra.parseCatchClause);
8118 parseComputedMember = wrapTracking(extra.parseComputedMember);
8119 parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
8120 parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
8121 parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
8122 parseExpression = wrapTracking(extra.parseExpression);
8123 parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
8124 parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
8125 parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
8126 parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression);
8127 parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
8128 parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
8129 parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
8130 parseNewExpression = wrapTracking(extra.parseNewExpression);
8131 parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
8132 parseObjectProperty = wrapTracking(extra.parseObjectProperty);
8133 parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
8134 parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
8135 parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
8136 parseProgram = wrapTracking(extra.parseProgram);
8137 parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
8138 parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
8139 parseStatement = wrapTracking(extra.parseStatement);
8140 parseShiftExpression = wrapTracking(extra.parseShiftExpression);
8141 parseSwitchCase = wrapTracking(extra.parseSwitchCase);
8142 parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
8143 parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
8144 parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
8147 if (typeof extra.tokens !== 'undefined') {
8148 extra.advance = advance;
8149 extra.scanRegExp = scanRegExp;
8151 advance = collectToken;
8152 scanRegExp = collectRegex;
8156 function unpatch() {
8157 if (typeof extra.skipComment === 'function') {
8158 skipComment = extra.skipComment;
8162 createLiteral = extra.createLiteral;
8165 if (extra.range || extra.loc) {
8166 parseAdditiveExpression = extra.parseAdditiveExpression;
8167 parseAssignmentExpression = extra.parseAssignmentExpression;
8168 parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
8169 parseBitwiseORExpression = extra.parseBitwiseORExpression;
8170 parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
8171 parseBlock = extra.parseBlock;
8172 parseFunctionSourceElements = extra.parseFunctionSourceElements;
8173 parseCatchClause = extra.parseCatchClause;
8174 parseComputedMember = extra.parseComputedMember;
8175 parseConditionalExpression = extra.parseConditionalExpression;
8176 parseConstLetDeclaration = extra.parseConstLetDeclaration;
8177 parseEqualityExpression = extra.parseEqualityExpression;
8178 parseExpression = extra.parseExpression;
8179 parseForVariableDeclaration = extra.parseForVariableDeclaration;
8180 parseFunctionDeclaration = extra.parseFunctionDeclaration;
8181 parseFunctionExpression = extra.parseFunctionExpression;
8182 parseGroupExpression = extra.parseGroupExpression;
8183 parseLeftHandSideExpression = extra.parseLeftHandSideExpression;
8184 parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall;
8185 parseLogicalANDExpression = extra.parseLogicalANDExpression;
8186 parseLogicalORExpression = extra.parseLogicalORExpression;
8187 parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
8188 parseNewExpression = extra.parseNewExpression;
8189 parseNonComputedProperty = extra.parseNonComputedProperty;
8190 parseObjectProperty = extra.parseObjectProperty;
8191 parseObjectPropertyKey = extra.parseObjectPropertyKey;
8192 parsePrimaryExpression = extra.parsePrimaryExpression;
8193 parsePostfixExpression = extra.parsePostfixExpression;
8194 parseProgram = extra.parseProgram;
8195 parsePropertyFunction = extra.parsePropertyFunction;
8196 parseRelationalExpression = extra.parseRelationalExpression;
8197 parseStatement = extra.parseStatement;
8198 parseShiftExpression = extra.parseShiftExpression;
8199 parseSwitchCase = extra.parseSwitchCase;
8200 parseUnaryExpression = extra.parseUnaryExpression;
8201 parseVariableDeclaration = extra.parseVariableDeclaration;
8202 parseVariableIdentifier = extra.parseVariableIdentifier;
8205 if (typeof extra.scanRegExp === 'function') {
8206 advance = extra.advance;
8207 scanRegExp = extra.scanRegExp;
8211 function stringToArray(str) {
8212 var length = str.length,
8215 for (i = 0; i < length; ++i) {
8216 result[i] = str.charAt(i);
8221 function parse(code, options) {
8222 var program, toString;
8225 if (typeof code !== 'string' && !(code instanceof String)) {
8226 code = toString(code);
8231 lineNumber = (source.length > 0) ? 1 : 0;
8233 length = source.length;
8238 inFunctionBody: false,
8244 if (typeof options !== 'undefined') {
8245 extra.range = (typeof options.range === 'boolean') && options.range;
8246 extra.loc = (typeof options.loc === 'boolean') && options.loc;
8247 extra.raw = (typeof options.raw === 'boolean') && options.raw;
8248 if (typeof options.tokens === 'boolean' && options.tokens) {
8251 if (typeof options.comment === 'boolean' && options.comment) {
8252 extra.comments = [];
8254 if (typeof options.tolerant === 'boolean' && options.tolerant) {
8260 if (typeof source[0] === 'undefined') {
8261 // Try first to convert to a string. This is good as fast path
8262 // for old IE which understands string indexing for string
8263 // literals only and not for string object.
8264 if (code instanceof String) {
8265 source = code.valueOf();
8268 // Force accessing the characters via an array.
8269 if (typeof source[0] === 'undefined') {
8270 source = stringToArray(code);
8277 program = parseProgram();
8278 if (typeof extra.comments !== 'undefined') {
8279 filterCommentLocation();
8280 program.comments = extra.comments;
8282 if (typeof extra.tokens !== 'undefined') {
8283 filterTokenLocation();
8284 program.tokens = extra.tokens;
8286 if (typeof extra.errors !== 'undefined') {
8287 program.errors = extra.errors;
8289 if (extra.range || extra.loc) {
8290 program.body = filterGroup(program.body);
8302 // Sync with package.json.
8303 exports.version = '1.0.3';
8305 exports.parse = parse;
8308 exports.Syntax = (function () {
8309 var name, types = {};
8311 if (typeof Object.create === 'function') {
8312 types = Object.create(null);
8315 for (name in Syntax) {
8316 if (Syntax.hasOwnProperty(name)) {
8317 types[name] = Syntax[name];
8321 if (typeof Object.freeze === 'function') {
8322 Object.freeze(types);
8329 /* vim: set sw=4 ts=4 et tw=80 : */
8331 * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
8332 * Available via the MIT or new BSD license.
8333 * see: http://github.com/jrburke/requirejs for details
8336 /*global define, Reflect */
8339 * xpcshell has a smaller stack on linux and windows (1MB vs 9MB on mac),
8340 * and the recursive nature of esprima can cause it to overflow pretty
8341 * quickly. So favor it built in Reflect parser:
8342 * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
8344 define('esprimaAdapter', ['./esprima', 'env'], function (esprima, env) {
8345 if (env.get() === 'xpconnect' && typeof Reflect !== 'undefined') {
8351 define('uglifyjs/consolidator', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
8353 * @preserve Copyright 2012 Robert Gust-Bardon <http://robert.gust-bardon.org/>.
8354 * All rights reserved.
8356 * Redistribution and use in source and binary forms, with or without
8357 * modification, are permitted provided that the following conditions
8360 * * Redistributions of source code must retain the above
8361 * copyright notice, this list of conditions and the following
8364 * * Redistributions in binary form must reproduce the above
8365 * copyright notice, this list of conditions and the following
8366 * disclaimer in the documentation and/or other materials
8367 * provided with the distribution.
8369 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
8370 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8371 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
8372 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
8373 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
8374 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
8375 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
8376 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
8377 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
8378 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
8379 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8384 * @fileoverview Enhances <a href="https://github.com/mishoo/UglifyJS/"
8385 * >UglifyJS</a> with consolidation of null, Boolean, and String values.
8386 * <p>Also known as aliasing, this feature has been deprecated in <a href=
8387 * "http://closure-compiler.googlecode.com/">the Closure Compiler</a> since its
8388 * initial release, where it is unavailable from the <abbr title=
8389 * "command line interface">CLI</a>. The Closure Compiler allows one to log and
8390 * influence this process. In contrast, this implementation does not introduce
8391 * any variable declarations in global code and derives String values from
8392 * identifier names used as property accessors.</p>
8393 * <p>Consolidating literals may worsen the data compression ratio when an <a
8394 * href="http://tools.ietf.org/html/rfc2616#section-3.5">encoding
8395 * transformation</a> is applied. For instance, <a href=
8396 * "http://code.jquery.com/jquery-1.7.1.js">jQuery 1.7.1</a> takes 248235 bytes.
8397 * Building it with <a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">
8398 * UglifyJS v1.2.5</a> results in 93647 bytes (37.73% of the original) which are
8399 * then compressed to 33154 bytes (13.36% of the original) using <a href=
8400 * "http://linux.die.net/man/1/gzip">gzip(1)</a>. Building it with the same
8401 * version of UglifyJS 1.2.5 patched with the implementation of consolidation
8402 * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison
8403 * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes
8404 * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned
8406 * <p>Written in <a href="http://es5.github.com/#x4.2.2">the strict variant</a>
8407 * of <a href="http://es5.github.com/">ECMA-262 5.1 Edition</a>. Encoded in <a
8408 * href="http://tools.ietf.org/html/rfc3629">UTF-8</a>. Follows <a href=
8409 * "http://google-styleguide.googlecode.com/svn-history/r76/trunk/javascriptguide.xml"
8410 * >Revision 2.28 of the Google JavaScript Style Guide</a> (except for the
8411 * discouraged use of the {@code function} tag and the {@code namespace} tag).
8412 * 100% typed for the <a href=
8413 * "http://closure-compiler.googlecode.com/files/compiler-20120123.tar.gz"
8414 * >Closure Compiler Version 1741</a>.</p>
8415 * <p>Should you find this software useful, please consider <a href=
8416 * "https://paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JZLW72X8FD4WG"
8417 * >a donation</a>.</p>
8418 * @author follow.me@RGustBardon (Robert Gust-Bardon)
8419 * @supported Tested with:
8421 * <li><a href="http://nodejs.org/dist/v0.6.10/">Node v0.6.10</a>,</li>
8422 * <li><a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">UglifyJS
8427 /*global console:false, exports:true, module:false, require:false */
8428 /*jshint sub:true */
8430 * Consolidates null, Boolean, and String values found inside an <abbr title=
8431 * "abstract syntax tree">AST</abbr>.
8432 * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object
8433 * representing an <abbr title="abstract syntax tree">AST</abbr>.
8434 * @return {!TSyntacticCodeUnit} An array-like object representing an <abbr
8435 * title="abstract syntax tree">AST</abbr> with its null, Boolean, and
8436 * String values consolidated.
8438 // TODO(user) Consolidation of mathematical values found in numeric literals.
8439 // TODO(user) Unconsolidation.
8440 // TODO(user) Consolidation of ECMA-262 6th Edition programs.
8441 // TODO(user) Rewrite in ECMA-262 6th Edition.
8442 exports['ast_consolidate'] = function(oAbstractSyntaxTree) {
8444 /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
8445 latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
8446 onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
8447 sub:false, trailing:true */
8451 * A record consisting of data about one or more source elements.
8455 TSourceElementsData = function() {
8457 * The category of the elements.
8459 * @see ESourceElementCategories
8461 this.nCategory = ESourceElementCategories.N_OTHER;
8463 * The number of occurrences (within the elements) of each primitive
8464 * value that could be consolidated.
8465 * @type {!Array.<!Object.<string, number>>}
8468 this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {};
8469 this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {};
8470 this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] =
8473 * Identifier names found within the elements.
8474 * @type {!Array.<string>}
8476 this.aIdentifiers = [];
8478 * Prefixed representation Strings of each primitive value that could be
8479 * consolidated within the elements.
8480 * @type {!Array.<string>}
8482 this.aPrimitiveValues = [];
8485 * A record consisting of data about a primitive value that could be
8490 TPrimitiveValue = function() {
8492 * The difference in the number of terminal symbols between the original
8493 * source text and the one with the primitive value consolidated. If the
8494 * difference is positive, the primitive value is considered worthwhile.
8499 * An identifier name of the variable that will be declared and assigned
8500 * the primitive value if the primitive value is consolidated.
8506 * A record consisting of data on what to consolidate within the range of
8507 * source elements that is currently being considered.
8511 TSolution = function() {
8513 * An object whose keys are prefixed representation Strings of each
8514 * primitive value that could be consolidated within the elements and
8515 * whose values are corresponding data about those primitive values.
8516 * @type {!Object.<string, {nSaving: number, sName: string}>}
8517 * @see TPrimitiveValue
8519 this.oPrimitiveValues = {};
8521 * The difference in the number of terminal symbols between the original
8522 * source text and the one with all the worthwhile primitive values
8525 * @see TPrimitiveValue#nSaving
8530 * The processor of <abbr title="abstract syntax tree">AST</abbr>s found
8533 * @type {!TProcessor}
8535 oProcessor = (/** @type {!TProcessor} */ require('./process')),
8537 * A record consisting of a number of constants that represent the
8538 * difference in the number of terminal symbols between a source text with
8539 * a modified syntactic code unit and the original one.
8541 * @type {!Object.<string, number>}
8545 * The difference in the number of punctuators required by the bracket
8546 * notation and the dot notation.
8547 * <p><code>'[]'.length - '.'.length</code></p>
8551 N_PROPERTY_ACCESSOR: 1,
8553 * The number of punctuators required by a variable declaration with an
8555 * <p><code>':'.length + ';'.length</code></p>
8559 N_VARIABLE_DECLARATION: 2,
8561 * The number of terminal symbols required to introduce a variable
8562 * statement (excluding its variable declaration list).
8563 * <p><code>'var '.length</code></p>
8567 N_VARIABLE_STATEMENT_AFFIXATION: 4,
8569 * The number of terminal symbols needed to enclose source elements
8570 * within a function call with no argument values to a function with an
8571 * empty parameter list.
8572 * <p><code>'(function(){}());'.length</code></p>
8579 * Categories of primary expressions from which primitive values that
8580 * could be consolidated are derivable.
8584 EPrimaryExpressionCategories = {
8586 * Identifier names used as property accessors.
8589 N_IDENTIFIER_NAMES: 0,
8594 N_STRING_LITERALS: 1,
8596 * Null and Boolean literals.
8599 N_NULL_AND_BOOLEAN_LITERALS: 2
8602 * Prefixes of primitive values that could be consolidated.
8603 * The String values of the prefixes must have same number of characters.
8604 * The prefixes must not be used in any properties defined in any version
8606 * "http://www.ecma-international.org/publications/standards/Ecma-262.htm"
8613 * Identifies String values.
8618 * Identifies null and Boolean values.
8624 * Categories of source elements in terms of their appropriateness of
8625 * having their primitive values consolidated.
8629 ESourceElementCategories = {
8631 * Identifies a source element that includes the <a href=
8632 * "http://es5.github.com/#x12.10">{@code with}</a> statement.
8637 * Identifies a source element that includes the <a href=
8638 * "http://es5.github.com/#x15.1.2.1">{@code eval}</a> identifier name.
8643 * Identifies a source element that must be excluded from the process
8644 * unless its whole scope is examined.
8649 * Identifies source elements not posing any problems.
8655 * The list of literals (other than the String ones) whose primitive
8656 * values can be consolidated.
8658 * @type {!Array.<string>}
8660 A_OTHER_SUBSTITUTABLE_LITERALS = [
8661 'null', // The null literal.
8662 'false', // The Boolean literal {@code false}.
8663 'true' // The Boolean literal {@code true}.
8667 * Consolidates all worthwhile primitive values in a syntactic code unit.
8668 * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object
8669 * representing the branch of the abstract syntax tree representing the
8670 * syntactic code unit along with its scope.
8671 * @see TPrimitiveValue#nSaving
8673 function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) {
8676 * Indicates whether the syntactic code unit represents global code.
8679 bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0],
8681 * Indicates whether the whole scope is being examined.
8684 bIsWhollyExaminable = !bIsGlobal,
8686 * An array-like object representing source elements that constitute a
8687 * syntactic code unit.
8688 * @type {!TSyntacticCodeUnit}
8692 * A record consisting of data about the source element that is
8693 * currently being examined.
8694 * @type {!TSourceElementsData}
8698 * The scope of the syntactic code unit.
8703 * An instance of an object that allows the traversal of an <abbr
8704 * title="abstract syntax tree">AST</abbr>.
8709 * An object encompassing collections of functions used during the
8710 * traversal of an <abbr title="abstract syntax tree">AST</abbr>.
8712 * @type {!Object.<string, !Object.<string, function(...[*])>>}
8716 * A collection of functions used during the surveyance of source
8719 * @type {!Object.<string, function(...[*])>}
8721 oSurveySourceElement: {
8722 /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
8724 * Classifies the source element as excludable if it does not
8725 * contain a {@code with} statement or the {@code eval} identifier
8726 * name. Adds the identifier of the function and its formal
8727 * parameters to the list of identifier names found.
8728 * @param {string} sIdentifier The identifier of the function.
8729 * @param {!Array.<string>} aFormalParameterList Formal parameters.
8730 * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
8734 aFormalParameterList,
8736 fClassifyAsExcludable();
8737 fAddIdentifier(sIdentifier);
8738 aFormalParameterList.forEach(fAddIdentifier);
8741 * Increments the count of the number of occurrences of the String
8742 * value that is equivalent to the sequence of terminal symbols
8743 * that constitute the encountered identifier name.
8744 * @param {!TSyntacticCodeUnit} oExpression The nonterminal
8746 * @param {string} sIdentifierName The identifier name used as the
8747 * property accessor.
8748 * @return {!Array} The encountered branch of an <abbr title=
8749 * "abstract syntax tree">AST</abbr> with its nonterminal
8750 * MemberExpression traversed.
8752 'dot': function(oExpression, sIdentifierName) {
8753 fCountPrimaryExpression(
8754 EPrimaryExpressionCategories.N_IDENTIFIER_NAMES,
8755 EValuePrefixes.S_STRING + sIdentifierName);
8756 return ['dot', oWalker.walk(oExpression), sIdentifierName];
8759 * Adds the optional identifier of the function and its formal
8760 * parameters to the list of identifier names found.
8761 * @param {?string} sIdentifier The optional identifier of the
8763 * @param {!Array.<string>} aFormalParameterList Formal parameters.
8764 * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
8766 'function': function(
8768 aFormalParameterList,
8770 if ('string' === typeof sIdentifier) {
8771 fAddIdentifier(sIdentifier);
8773 aFormalParameterList.forEach(fAddIdentifier);
8776 * Either increments the count of the number of occurrences of the
8777 * encountered null or Boolean value or classifies a source element
8778 * as containing the {@code eval} identifier name.
8779 * @param {string} sIdentifier The identifier encountered.
8781 'name': function(sIdentifier) {
8782 if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) {
8783 fCountPrimaryExpression(
8784 EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS,
8785 EValuePrefixes.S_SYMBOLIC + sIdentifier);
8787 if ('eval' === sIdentifier) {
8788 oSourceElementData.nCategory =
8789 ESourceElementCategories.N_EVAL;
8791 fAddIdentifier(sIdentifier);
8795 * Classifies the source element as excludable if it does not
8796 * contain a {@code with} statement or the {@code eval} identifier
8798 * @param {TSyntacticCodeUnit} oExpression The expression whose
8799 * value is to be returned.
8801 'return': function(oExpression) {
8802 fClassifyAsExcludable();
8805 * Increments the count of the number of occurrences of the
8806 * encountered String value.
8807 * @param {string} sStringValue The String value of the string
8808 * literal encountered.
8810 'string': function(sStringValue) {
8811 if (sStringValue.length > 0) {
8812 fCountPrimaryExpression(
8813 EPrimaryExpressionCategories.N_STRING_LITERALS,
8814 EValuePrefixes.S_STRING + sStringValue);
8818 * Adds the identifier reserved for an exception to the list of
8819 * identifier names found.
8820 * @param {!TSyntacticCodeUnit} oTry A block of code in which an
8821 * exception can occur.
8822 * @param {Array} aCatch The identifier reserved for an exception
8823 * and a block of code to handle the exception.
8824 * @param {TSyntacticCodeUnit} oFinally An optional block of code
8825 * to be evaluated regardless of whether an exception occurs.
8827 'try': function(oTry, aCatch, oFinally) {
8828 if (Array.isArray(aCatch)) {
8829 fAddIdentifier(aCatch[0]);
8833 * Classifies the source element as excludable if it does not
8834 * contain a {@code with} statement or the {@code eval} identifier
8835 * name. Adds the identifier of each declared variable to the list
8836 * of identifier names found.
8837 * @param {!Array.<!Array>} aVariableDeclarationList Variable
8840 'var': function(aVariableDeclarationList) {
8841 fClassifyAsExcludable();
8842 aVariableDeclarationList.forEach(fAddVariable);
8845 * Classifies a source element as containing the {@code with}
8847 * @param {!TSyntacticCodeUnit} oExpression An expression whose
8848 * value is to be converted to a value of type Object and
8849 * become the binding object of a new object environment
8850 * record of a new lexical environment in which the statement
8851 * is to be executed.
8852 * @param {!TSyntacticCodeUnit} oStatement The statement to be
8853 * executed in the augmented lexical environment.
8854 * @return {!Array} An empty array to stop the traversal.
8856 'with': function(oExpression, oStatement) {
8857 oSourceElementData.nCategory = ESourceElementCategories.N_WITH;
8860 /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
8863 * A collection of functions used while looking for nested functions.
8865 * @type {!Object.<string, function(...[*])>}
8867 oExamineFunctions: {
8868 /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
8870 * Orders an examination of a nested function declaration.
8871 * @this {!TSyntacticCodeUnit} An array-like object representing
8872 * the branch of an <abbr title="abstract syntax tree"
8873 * >AST</abbr> representing the syntactic code unit along with
8875 * @return {!Array} An empty array to stop the traversal.
8877 'defun': function() {
8878 fExamineSyntacticCodeUnit(this);
8882 * Orders an examination of a nested function expression.
8883 * @this {!TSyntacticCodeUnit} An array-like object representing
8884 * the branch of an <abbr title="abstract syntax tree"
8885 * >AST</abbr> representing the syntactic code unit along with
8887 * @return {!Array} An empty array to stop the traversal.
8889 'function': function() {
8890 fExamineSyntacticCodeUnit(this);
8893 /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
8897 * Records containing data about source elements.
8898 * @type {Array.<TSourceElementsData>}
8900 aSourceElementsData = [],
8902 * The index (in the source text order) of the source element
8903 * immediately following a <a href="http://es5.github.com/#x14.1"
8904 * >Directive Prologue</a>.
8907 nAfterDirectivePrologue = 0,
8909 * The index (in the source text order) of the source element that is
8910 * currently being considered.
8915 * The index (in the source text order) of the source element that is
8916 * the last element of the range of source elements that is currently
8918 * @type {(undefined|number)}
8922 * Initiates the traversal of a source element.
8923 * @param {!TWalker} oWalker An instance of an object that allows the
8924 * traversal of an abstract syntax tree.
8925 * @param {!TSyntacticCodeUnit} oSourceElement A source element from
8926 * which the traversal should commence.
8927 * @return {function(): !TSyntacticCodeUnit} A function that is able to
8928 * initiate the traversal from a given source element.
8930 cContext = function(oWalker, oSourceElement) {
8932 * @return {!TSyntacticCodeUnit} A function that is able to
8933 * initiate the traversal from a given source element.
8935 var fLambda = function() {
8936 return oWalker.walk(oSourceElement);
8942 * Classifies the source element as excludable if it does not
8943 * contain a {@code with} statement or the {@code eval} identifier
8946 fClassifyAsExcludable = function() {
8947 if (oSourceElementData.nCategory ===
8948 ESourceElementCategories.N_OTHER) {
8949 oSourceElementData.nCategory =
8950 ESourceElementCategories.N_EXCLUDABLE;
8954 * Adds an identifier to the list of identifier names found.
8955 * @param {string} sIdentifier The identifier to be added.
8957 fAddIdentifier = function(sIdentifier) {
8958 if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) {
8959 oSourceElementData.aIdentifiers.push(sIdentifier);
8963 * Adds the identifier of a variable to the list of identifier names
8965 * @param {!Array} aVariableDeclaration A variable declaration.
8967 fAddVariable = function(aVariableDeclaration) {
8968 fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]);
8971 * Increments the count of the number of occurrences of the prefixed
8972 * String representation attributed to the primary expression.
8973 * @param {number} nCategory The category of the primary expression.
8974 * @param {string} sName The prefixed String representation attributed
8975 * to the primary expression.
8977 fCountPrimaryExpression = function(nCategory, sName) {
8978 if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) {
8979 oSourceElementData.aCount[nCategory][sName] = 0;
8980 if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) {
8981 oSourceElementData.aPrimitiveValues.push(sName);
8984 oSourceElementData.aCount[nCategory][sName] += 1;
8987 * Consolidates all worthwhile primitive values in a range of source
8989 * @param {number} nFrom The index (in the source text order) of the
8990 * source element that is the first element of the range.
8991 * @param {number} nTo The index (in the source text order) of the
8992 * source element that is the last element of the range.
8993 * @param {boolean} bEnclose Indicates whether the range should be
8994 * enclosed within a function call with no argument values to a
8995 * function with an empty parameter list if any primitive values
8997 * @see TPrimitiveValue#nSaving
8999 fExamineSourceElements = function(nFrom, nTo, bEnclose) {
9002 * The index of the last mangled name.
9005 nIndex = oScope.cname,
9007 * The index of the source element that is currently being
9013 * A collection of functions used during the consolidation of
9014 * primitive values and identifier names used as property
9017 * @type {!Object.<string, function(...[*])>}
9019 oWalkersTransformers = {
9021 * If the String value that is equivalent to the sequence of
9022 * terminal symbols that constitute the encountered identifier
9023 * name is worthwhile, a syntactic conversion from the dot
9024 * notation to the bracket notation ensues with that sequence
9025 * being substituted by an identifier name to which the value
9027 * Applies to property accessors that use the dot notation.
9028 * @param {!TSyntacticCodeUnit} oExpression The nonterminal
9030 * @param {string} sIdentifierName The identifier name used as
9031 * the property accessor.
9032 * @return {!Array} A syntactic code unit that is equivalent to
9033 * the one encountered.
9034 * @see TPrimitiveValue#nSaving
9036 'dot': function(oExpression, sIdentifierName) {
9038 * The prefixed String value that is equivalent to the
9039 * sequence of terminal symbols that constitute the
9040 * encountered identifier name.
9043 var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName;
9045 return oSolutionBest.oPrimitiveValues.hasOwnProperty(
9047 oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
9049 oWalker.walk(oExpression),
9051 oSolutionBest.oPrimitiveValues[sPrefixed].sName]] :
9052 ['dot', oWalker.walk(oExpression), sIdentifierName];
9055 * If the encountered identifier is a null or Boolean literal
9056 * and its value is worthwhile, the identifier is substituted
9057 * by an identifier name to which that value is assigned.
9058 * Applies to identifier names.
9059 * @param {string} sIdentifier The identifier encountered.
9060 * @return {!Array} A syntactic code unit that is equivalent to
9061 * the one encountered.
9062 * @see TPrimitiveValue#nSaving
9064 'name': function(sIdentifier) {
9066 * The prefixed representation String of the identifier.
9069 var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier;
9073 oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) &&
9074 oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
9075 oSolutionBest.oPrimitiveValues[sPrefixed].sName :
9080 * If the encountered String value is worthwhile, it is
9081 * substituted by an identifier name to which that value is
9083 * Applies to String values.
9084 * @param {string} sStringValue The String value of the string
9085 * literal encountered.
9086 * @return {!Array} A syntactic code unit that is equivalent to
9087 * the one encountered.
9088 * @see TPrimitiveValue#nSaving
9090 'string': function(sStringValue) {
9092 * The prefixed representation String of the primitive value
9097 EValuePrefixes.S_STRING + sStringValue;
9099 return oSolutionBest.oPrimitiveValues.hasOwnProperty(
9101 oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
9103 oSolutionBest.oPrimitiveValues[sPrefixed].sName] :
9104 ['string', sStringValue];
9108 * Such data on what to consolidate within the range of source
9109 * elements that is currently being considered that lead to the
9110 * greatest known reduction of the number of the terminal symbols
9111 * in comparison to the original source text.
9112 * @type {!TSolution}
9114 oSolutionBest = new TSolution(),
9116 * Data representing an ongoing attempt to find a better
9117 * reduction of the number of the terminal symbols in comparison
9118 * to the original source text than the best one that is
9120 * @type {!TSolution}
9121 * @see oSolutionBest
9123 oSolutionCandidate = new TSolution(),
9125 * A record consisting of data about the range of source elements
9126 * that is currently being examined.
9127 * @type {!TSourceElementsData}
9129 oSourceElementsData = new TSourceElementsData(),
9131 * Variable declarations for each primitive value that is to be
9132 * consolidated within the elements.
9133 * @type {!Array.<!Array>}
9135 aVariableDeclarations = [],
9137 * Augments a list with a prefixed representation String.
9138 * @param {!Array.<string>} aList A list that is to be augmented.
9139 * @return {function(string)} A function that augments a list
9140 * with a prefixed representation String.
9142 cAugmentList = function(aList) {
9144 * @param {string} sPrefixed Prefixed representation String of
9145 * a primitive value that could be consolidated within the
9148 var fLambda = function(sPrefixed) {
9149 if (-1 === aList.indexOf(sPrefixed)) {
9150 aList.push(sPrefixed);
9157 * Adds the number of occurrences of a primitive value of a given
9158 * category that could be consolidated in the source element with
9159 * a given index to the count of occurrences of that primitive
9160 * value within the range of source elements that is currently
9162 * @param {number} nPosition The index (in the source text order)
9163 * of a source element.
9164 * @param {number} nCategory The category of the primary
9165 * expression from which the primitive value is derived.
9166 * @return {function(string)} A function that performs the
9168 * @see cAddOccurrencesInCategory
9170 cAddOccurrences = function(nPosition, nCategory) {
9172 * @param {string} sPrefixed The prefixed representation String
9173 * of a primitive value.
9175 var fLambda = function(sPrefixed) {
9176 if (!oSourceElementsData.aCount[nCategory].hasOwnProperty(
9178 oSourceElementsData.aCount[nCategory][sPrefixed] = 0;
9180 oSourceElementsData.aCount[nCategory][sPrefixed] +=
9181 aSourceElementsData[nPosition].aCount[nCategory][
9188 * Adds the number of occurrences of each primitive value of a
9189 * given category that could be consolidated in the source
9190 * element with a given index to the count of occurrences of that
9191 * primitive values within the range of source elements that is
9192 * currently being considered.
9193 * @param {number} nPosition The index (in the source text order)
9194 * of a source element.
9195 * @return {function(number)} A function that performs the
9197 * @see fAddOccurrences
9199 cAddOccurrencesInCategory = function(nPosition) {
9201 * @param {number} nCategory The category of the primary
9202 * expression from which the primitive value is derived.
9204 var fLambda = function(nCategory) {
9206 aSourceElementsData[nPosition].aCount[nCategory]
9207 ).forEach(cAddOccurrences(nPosition, nCategory));
9213 * Adds the number of occurrences of each primitive value that
9214 * could be consolidated in the source element with a given index
9215 * to the count of occurrences of that primitive values within
9216 * the range of source elements that is currently being
9218 * @param {number} nPosition The index (in the source text order)
9219 * of a source element.
9221 fAddOccurrences = function(nPosition) {
9222 Object.keys(aSourceElementsData[nPosition].aCount).forEach(
9223 cAddOccurrencesInCategory(nPosition));
9226 * Creates a variable declaration for a primitive value if that
9227 * primitive value is to be consolidated within the elements.
9228 * @param {string} sPrefixed Prefixed representation String of a
9229 * primitive value that could be consolidated within the
9231 * @see aVariableDeclarations
9233 cAugmentVariableDeclarations = function(sPrefixed) {
9234 if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) {
9235 aVariableDeclarations.push([
9236 oSolutionBest.oPrimitiveValues[sPrefixed].sName,
9237 [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ?
9239 sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)]
9244 * Sorts primitive values with regard to the difference in the
9245 * number of terminal symbols between the original source text
9246 * and the one with those primitive values consolidated.
9247 * @param {string} sPrefixed0 The prefixed representation String
9248 * of the first of the two primitive values that are being
9250 * @param {string} sPrefixed1 The prefixed representation String
9251 * of the second of the two primitive values that are being
9256 * <dd>if the first primitive value must be placed before
9257 * the other one,</dd>
9259 * <dd>if the first primitive value may be placed before
9260 * the other one,</dd>
9262 * <dd>if the first primitive value must not be placed
9263 * before the other one.</dd>
9265 * @see TSolution.oPrimitiveValues
9267 cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) {
9269 * The difference between:
9271 * <li>the difference in the number of terminal symbols
9272 * between the original source text and the one with the
9273 * first primitive value consolidated, and</li>
9274 * <li>the difference in the number of terminal symbols
9275 * between the original source text and the one with the
9276 * second primitive value consolidated.</li>
9281 oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving -
9282 oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving;
9284 return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0;
9287 * Assigns an identifier name to a primitive value and calculates
9288 * whether instances of that primitive value are worth
9290 * @param {string} sPrefixed The prefixed representation String
9291 * of a primitive value that is being evaluated.
9293 fEvaluatePrimitiveValue = function(sPrefixed) {
9296 * The index of the last mangled name.
9301 * The representation String of the primitive value that is
9306 sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length),
9308 * The number of source characters taken up by the
9309 * representation String of the primitive value that is
9313 nLengthOriginal = sName.length,
9315 * The number of source characters taken up by the
9316 * identifier name that could substitute the primitive
9317 * value that is being evaluated.
9321 nLengthSubstitution,
9323 * The number of source characters taken up by by the
9324 * representation String of the primitive value that is
9325 * being evaluated when it is represented by a string
9329 nLengthString = oProcessor.make_string(sName).length;
9331 oSolutionCandidate.oPrimitiveValues[sPrefixed] =
9332 new TPrimitiveValue();
9333 do { // Find an identifier unused in this or any nested scope.
9334 nIndex = oScope.cname;
9335 oSolutionCandidate.oPrimitiveValues[sPrefixed].sName =
9336 oScope.next_mangled();
9337 } while (-1 !== oSourceElementsData.aIdentifiers.indexOf(
9338 oSolutionCandidate.oPrimitiveValues[sPrefixed].sName));
9339 nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[
9340 sPrefixed].sName.length;
9341 if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) {
9342 // foo:null, or foo:null;
9343 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
9344 nLengthSubstitution + nLengthOriginal +
9345 oWeights.N_VARIABLE_DECLARATION;
9347 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
9348 oSourceElementsData.aCount[
9349 EPrimaryExpressionCategories.
9350 N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] *
9351 (nLengthOriginal - nLengthSubstitution);
9353 // foo:'fromCharCode';
9354 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
9355 nLengthSubstitution + nLengthString +
9356 oWeights.N_VARIABLE_DECLARATION;
9357 // .fromCharCode vs [foo]
9358 if (oSourceElementsData.aCount[
9359 EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
9360 ].hasOwnProperty(sPrefixed)) {
9361 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
9362 oSourceElementsData.aCount[
9363 EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
9365 (nLengthOriginal - nLengthSubstitution -
9366 oWeights.N_PROPERTY_ACCESSOR);
9368 // 'fromCharCode' vs foo
9369 if (oSourceElementsData.aCount[
9370 EPrimaryExpressionCategories.N_STRING_LITERALS
9371 ].hasOwnProperty(sPrefixed)) {
9372 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
9373 oSourceElementsData.aCount[
9374 EPrimaryExpressionCategories.N_STRING_LITERALS
9376 (nLengthString - nLengthSubstitution);
9379 if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving >
9381 oSolutionCandidate.nSavings +=
9382 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving;
9384 oScope.cname = nIndex; // Free the identifier name.
9388 * Adds a variable declaration to an existing variable statement.
9389 * @param {!Array} aVariableDeclaration A variable declaration
9390 * with an initialiser.
9392 cAddVariableDeclaration = function(aVariableDeclaration) {
9393 (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift(
9394 aVariableDeclaration);
9400 // If the range is a closure, reuse the closure.
9401 if (nFrom === nTo &&
9402 'stat' === oSourceElements[nFrom][0] &&
9403 'call' === oSourceElements[nFrom][1][0] &&
9404 'function' === oSourceElements[nFrom][1][1][0]) {
9405 fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]);
9408 // Create a list of all derived primitive values within the range.
9409 for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
9410 aSourceElementsData[nPosition].aPrimitiveValues.forEach(
9411 cAugmentList(oSourceElementsData.aPrimitiveValues));
9413 if (0 === oSourceElementsData.aPrimitiveValues.length) {
9416 for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
9417 // Add the number of occurrences to the total count.
9418 fAddOccurrences(nPosition);
9419 // Add identifiers of this or any nested scope to the list.
9420 aSourceElementsData[nPosition].aIdentifiers.forEach(
9421 cAugmentList(oSourceElementsData.aIdentifiers));
9423 // Distribute identifier names among derived primitive values.
9424 do { // If there was any progress, find a better distribution.
9425 oSolutionBest = oSolutionCandidate;
9426 if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) {
9427 // Sort primitive values descending by their worthwhileness.
9428 oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues);
9430 oSolutionCandidate = new TSolution();
9431 oSourceElementsData.aPrimitiveValues.forEach(
9432 fEvaluatePrimitiveValue);
9433 oScope.cname = nIndex;
9434 } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings);
9435 // Take the necessity of adding a variable statement into account.
9436 if ('var' !== oSourceElements[nFrom][0]) {
9437 oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION;
9440 // Take the necessity of forming a closure into account.
9441 oSolutionBest.nSavings -= oWeights.N_CLOSURE;
9443 if (oSolutionBest.nSavings > 0) {
9444 // Create variable declarations suitable for UglifyJS.
9445 Object.keys(oSolutionBest.oPrimitiveValues).forEach(
9446 cAugmentVariableDeclarations);
9447 // Rewrite expressions that contain worthwhile primitive values.
9448 for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
9449 oWalker = oProcessor.ast_walker();
9450 oSourceElements[nPosition] =
9451 oWalker.with_walkers(
9452 oWalkersTransformers,
9453 cContext(oWalker, oSourceElements[nPosition]));
9455 if ('var' === oSourceElements[nFrom][0]) { // Reuse the statement.
9456 (/** @type {!Array.<!Array>} */ aVariableDeclarations.reverse(
9457 )).forEach(cAddVariableDeclaration);
9458 } else { // Add a variable statement.
9459 Array.prototype.splice.call(
9463 ['var', aVariableDeclarations]);
9468 Array.prototype.splice.call(
9472 ['stat', ['call', ['function', null, [], []], []]]);
9473 // Copy source elements into the closure.
9474 for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) {
9475 Array.prototype.unshift.call(
9476 oSourceElements[nFrom][1][1][3],
9477 oSourceElements[nPosition]);
9479 // Remove source elements outside the closure.
9480 Array.prototype.splice.call(
9487 // Restore the availability of identifier names.
9488 oScope.cname = nIndex;
9492 oSourceElements = (/** @type {!TSyntacticCodeUnit} */
9493 oSyntacticCodeUnit[bIsGlobal ? 1 : 3]);
9494 if (0 === oSourceElements.length) {
9497 oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope;
9498 // Skip a Directive Prologue.
9499 while (nAfterDirectivePrologue < oSourceElements.length &&
9500 'directive' === oSourceElements[nAfterDirectivePrologue][0]) {
9501 nAfterDirectivePrologue += 1;
9502 aSourceElementsData.push(null);
9504 if (oSourceElements.length === nAfterDirectivePrologue) {
9507 for (nPosition = nAfterDirectivePrologue;
9508 nPosition < oSourceElements.length;
9510 oSourceElementData = new TSourceElementsData();
9511 oWalker = oProcessor.ast_walker();
9512 // Classify a source element.
9513 // Find its derived primitive values and count their occurrences.
9514 // Find all identifiers used (including nested scopes).
9515 oWalker.with_walkers(
9516 oWalkers.oSurveySourceElement,
9517 cContext(oWalker, oSourceElements[nPosition]));
9518 // Establish whether the scope is still wholly examinable.
9519 bIsWhollyExaminable = bIsWhollyExaminable &&
9520 ESourceElementCategories.N_WITH !== oSourceElementData.nCategory &&
9521 ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory;
9522 aSourceElementsData.push(oSourceElementData);
9524 if (bIsWhollyExaminable) { // Examine the whole scope.
9525 fExamineSourceElements(
9526 nAfterDirectivePrologue,
9527 oSourceElements.length - 1,
9529 } else { // Examine unexcluded ranges of source elements.
9530 for (nPosition = oSourceElements.length - 1;
9531 nPosition >= nAfterDirectivePrologue;
9533 oSourceElementData = (/** @type {!TSourceElementsData} */
9534 aSourceElementsData[nPosition]);
9535 if (ESourceElementCategories.N_OTHER ===
9536 oSourceElementData.nCategory) {
9537 if ('undefined' === typeof nTo) {
9538 nTo = nPosition; // Indicate the end of a range.
9540 // Examine the range if it immediately follows a Directive Prologue.
9541 if (nPosition === nAfterDirectivePrologue) {
9542 fExamineSourceElements(nPosition, nTo, true);
9545 if ('undefined' !== typeof nTo) {
9546 // Examine the range that immediately follows this source element.
9547 fExamineSourceElements(nPosition + 1, nTo, true);
9548 nTo = void 0; // Obliterate the range.
9550 // Examine nested functions.
9551 oWalker = oProcessor.ast_walker();
9552 oWalker.with_walkers(
9553 oWalkers.oExamineFunctions,
9554 cContext(oWalker, oSourceElements[nPosition]));
9558 }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree)));
9559 return oAbstractSyntaxTree;
9561 /*jshint sub:false */
9563 /* Local Variables: */
9566 /* indent-tabs-mode: nil */
9569 /* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */
9570 /* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */
9572 define('uglifyjs/parse-js', ["exports"], function(exports) {
9573 /***********************************************************************
9575 A JavaScript tokenizer / parser / beautifier / compressor.
9577 This version is suitable for Node.js. With minimal changes (the
9578 exports stuff) it should work on any JS platform.
9580 This file contains the tokenizer/parser. It is a port to JavaScript
9581 of parse-js [1], a JavaScript parser library written in Common Lisp
9582 by Marijn Haverbeke. Thank you Marijn!
9584 [1] http://marijn.haverbeke.nl/parse-js/
9588 - tokenizer(code) -- returns a function. Call the returned
9589 function to fetch the next token.
9591 - parse(code) -- returns an AST of the given JavaScript code.
9593 -------------------------------- (C) ---------------------------------
9596 <mihai.bazon@gmail.com>
9597 http://mihai.bazon.net/blog
9599 Distributed under the BSD license:
9601 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
9602 Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
9604 Redistribution and use in source and binary forms, with or without
9605 modification, are permitted provided that the following conditions
9608 * Redistributions of source code must retain the above
9609 copyright notice, this list of conditions and the following
9612 * Redistributions in binary form must reproduce the above
9613 copyright notice, this list of conditions and the following
9614 disclaimer in the documentation and/or other materials
9615 provided with the distribution.
9617 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
9618 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9619 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
9620 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
9621 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
9622 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
9623 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
9624 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
9625 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
9626 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
9627 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9630 ***********************************************************************/
9632 /* -----[ Tokenizer (constants) ]----- */
9634 var KEYWORDS = array_to_hash([
9663 var RESERVED_WORDS = array_to_hash([
9695 var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
9704 var KEYWORDS_ATOM = array_to_hash([
9711 var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
9713 var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
9714 var RE_OCT_NUMBER = /^0[0-7]+$/;
9715 var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
9717 var OPERATORS = array_to_hash([
9764 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\uFEFF"));
9766 var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:"));
9768 var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
9770 var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
9772 /* -----[ Tokenizer ]----- */
9774 var UNICODE = { // Unicode 6.1
9775 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-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\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\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\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-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\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-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\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-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\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]"),
9776 combining_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u08E4-\\u08FE\\u0900-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C01-\\u0C03\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C82\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0D02\\u0D03\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D82\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF2-\\u1CF4\\u1DC0-\\u1DE6\\u1DFC-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA674-\\uA67D\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA880\\uA881\\uA8B4-\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
9777 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]"),
9778 digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]")
9781 function is_letter(ch) {
9782 return UNICODE.letter.test(ch);
9785 function is_digit(ch) {
9786 ch = ch.charCodeAt(0);
9787 return ch >= 48 && ch <= 57;
9790 function is_unicode_digit(ch) {
9791 return UNICODE.digit.test(ch);
9794 function is_alphanumeric_char(ch) {
9795 return is_digit(ch) || is_letter(ch);
9798 function is_unicode_combining_mark(ch) {
9799 return UNICODE.combining_mark.test(ch);
9802 function is_unicode_connector_punctuation(ch) {
9803 return UNICODE.connector_punctuation.test(ch);
9806 function is_identifier_start(ch) {
9807 return ch == "$" || ch == "_" || is_letter(ch);
9810 function is_identifier_char(ch) {
9811 return is_identifier_start(ch)
9812 || is_unicode_combining_mark(ch)
9813 || is_unicode_digit(ch)
9814 || is_unicode_connector_punctuation(ch)
9815 || ch == "\u200c" // zero-width non-joiner <ZWNJ>
9816 || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
9820 function parse_js_number(num) {
9821 if (RE_HEX_NUMBER.test(num)) {
9822 return parseInt(num.substr(2), 16);
9823 } else if (RE_OCT_NUMBER.test(num)) {
9824 return parseInt(num.substr(1), 8);
9825 } else if (RE_DEC_NUMBER.test(num)) {
9826 return parseFloat(num);
9830 function JS_Parse_Error(message, line, col, pos) {
9831 this.message = message;
9832 this.line = line + 1;
9835 this.stack = new Error().stack;
9838 JS_Parse_Error.prototype.toString = function() {
9839 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
9842 function js_error(message, line, col, pos) {
9843 throw new JS_Parse_Error(message, line, col, pos);
9846 function is_token(token, type, val) {
9847 return token.type == type && (val == null || token.value == val);
9852 function tokenizer($TEXT) {
9855 text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
9862 newline_before : false,
9863 regex_allowed : false,
9864 comments_before : []
9867 function peek() { return S.text.charAt(S.pos); };
9869 function next(signal_eof, in_string) {
9870 var ch = S.text.charAt(S.pos++);
9871 if (signal_eof && !ch)
9874 S.newline_before = S.newline_before || !in_string;
9887 function find(what, signal_eof) {
9888 var pos = S.text.indexOf(what, S.pos);
9889 if (signal_eof && pos == -1) throw EX_EOF;
9893 function start_token() {
9899 function token(type, value, is_comment) {
9900 S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
9901 (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
9902 (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
9910 nlb : S.newline_before
9913 ret.comments_before = S.comments_before;
9914 S.comments_before = [];
9915 // make note of any newlines in the comments that came before
9916 for (var i = 0, len = ret.comments_before.length; i < len; i++) {
9917 ret.nlb = ret.nlb || ret.comments_before[i].nlb;
9920 S.newline_before = false;
9924 function skip_whitespace() {
9925 while (HOP(WHITESPACE_CHARS, peek()))
9929 function read_while(pred) {
9930 var ret = "", ch = peek(), i = 0;
9931 while (ch && pred(ch, i++)) {
9938 function parse_error(err) {
9939 js_error(err, S.tokline, S.tokcol, S.tokpos);
9942 function read_num(prefix) {
9943 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
9944 var num = read_while(function(ch, i){
9945 if (ch == "x" || ch == "X") {
9946 if (has_x) return false;
9947 return has_x = true;
9949 if (!has_x && (ch == "E" || ch == "e")) {
9950 if (has_e) return false;
9951 return has_e = after_e = true;
9954 if (after_e || (i == 0 && !prefix)) return true;
9957 if (ch == "+") return after_e;
9960 if (!has_dot && !has_x && !has_e)
9961 return has_dot = true;
9964 return is_alphanumeric_char(ch);
9968 var valid = parse_js_number(num);
9969 if (!isNaN(valid)) {
9970 return token("num", valid);
9972 parse_error("Invalid syntax: " + num);
9976 function read_escaped_char(in_string) {
9977 var ch = next(true, in_string);
9979 case "n" : return "\n";
9980 case "r" : return "\r";
9981 case "t" : return "\t";
9982 case "b" : return "\b";
9983 case "v" : return "\u000b";
9984 case "f" : return "\f";
9985 case "0" : return "\0";
9986 case "x" : return String.fromCharCode(hex_bytes(2));
9987 case "u" : return String.fromCharCode(hex_bytes(4));
9988 case "\n": return "";
9989 default : return ch;
9993 function hex_bytes(n) {
9995 for (; n > 0; --n) {
9996 var digit = parseInt(next(true), 16);
9998 parse_error("Invalid hex-character pattern in string");
9999 num = (num << 4) | digit;
10004 function read_string() {
10005 return with_eof_error("Unterminated string constant", function(){
10006 var quote = next(), ret = "";
10008 var ch = next(true);
10010 // read OctalEscapeSequence (XXX: deprecated if "strict mode")
10011 // https://github.com/mishoo/UglifyJS/issues/178
10012 var octal_len = 0, first = null;
10013 ch = read_while(function(ch){
10014 if (ch >= "0" && ch <= "7") {
10017 return ++octal_len;
10019 else if (first <= "3" && octal_len <= 2) return ++octal_len;
10020 else if (first >= "4" && octal_len <= 1) return ++octal_len;
10024 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
10025 else ch = read_escaped_char(true);
10027 else if (ch == quote) break;
10028 else if (ch == "\n") throw EX_EOF;
10031 return token("string", ret);
10035 function read_line_comment() {
10037 var i = find("\n"), ret;
10039 ret = S.text.substr(S.pos);
10040 S.pos = S.text.length;
10042 ret = S.text.substring(S.pos, i);
10045 return token("comment1", ret, true);
10048 function read_multiline_comment() {
10050 return with_eof_error("Unterminated multiline comment", function(){
10051 var i = find("*/", true),
10052 text = S.text.substring(S.pos, i);
10054 S.line += text.split("\n").length - 1;
10055 S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
10057 // https://github.com/mishoo/UglifyJS/issues/#issue/100
10058 if (/^@cc_on/i.test(text)) {
10059 warn("WARNING: at line " + S.line);
10060 warn("*** Found \"conditional comment\": " + text);
10061 warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer.");
10064 return token("comment2", text, true);
10068 function read_name() {
10069 var backslash = false, name = "", ch, escaped = false, hex;
10070 while ((ch = peek()) != null) {
10072 if (ch == "\\") escaped = backslash = true, next();
10073 else if (is_identifier_char(ch)) name += next();
10077 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
10078 ch = read_escaped_char();
10079 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
10084 if (HOP(KEYWORDS, name) && escaped) {
10085 hex = name.charCodeAt(0).toString(16).toUpperCase();
10086 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
10091 function read_regexp(regexp) {
10092 return with_eof_error("Unterminated regular expression", function(){
10093 var prev_backslash = false, ch, in_class = false;
10094 while ((ch = next(true))) if (prev_backslash) {
10095 regexp += "\\" + ch;
10096 prev_backslash = false;
10097 } else if (ch == "[") {
10100 } else if (ch == "]" && in_class) {
10103 } else if (ch == "/" && !in_class) {
10105 } else if (ch == "\\") {
10106 prev_backslash = true;
10110 var mods = read_name();
10111 return token("regexp", [ regexp, mods ]);
10115 function read_operator(prefix) {
10116 function grow(op) {
10117 if (!peek()) return op;
10118 var bigger = op + peek();
10119 if (HOP(OPERATORS, bigger)) {
10121 return grow(bigger);
10126 return token("operator", grow(prefix || next()));
10129 function handle_slash() {
10131 var regex_allowed = S.regex_allowed;
10134 S.comments_before.push(read_line_comment());
10135 S.regex_allowed = regex_allowed;
10136 return next_token();
10138 S.comments_before.push(read_multiline_comment());
10139 S.regex_allowed = regex_allowed;
10140 return next_token();
10142 return S.regex_allowed ? read_regexp("") : read_operator("/");
10145 function handle_dot() {
10147 return is_digit(peek())
10149 : token("punc", ".");
10152 function read_word() {
10153 var word = read_name();
10154 return !HOP(KEYWORDS, word)
10155 ? token("name", word)
10156 : HOP(OPERATORS, word)
10157 ? token("operator", word)
10158 : HOP(KEYWORDS_ATOM, word)
10159 ? token("atom", word)
10160 : token("keyword", word);
10163 function with_eof_error(eof_error, cont) {
10167 if (ex === EX_EOF) parse_error(eof_error);
10172 function next_token(force_regexp) {
10173 if (force_regexp != null)
10174 return read_regexp(force_regexp);
10178 if (!ch) return token("eof");
10179 if (is_digit(ch)) return read_num();
10180 if (ch == '"' || ch == "'") return read_string();
10181 if (HOP(PUNC_CHARS, ch)) return token("punc", next());
10182 if (ch == ".") return handle_dot();
10183 if (ch == "/") return handle_slash();
10184 if (HOP(OPERATOR_CHARS, ch)) return read_operator();
10185 if (ch == "\\" || is_identifier_start(ch)) return read_word();
10186 parse_error("Unexpected character '" + ch + "'");
10189 next_token.context = function(nc) {
10198 /* -----[ Parser (constants) ]----- */
10200 var UNARY_PREFIX = array_to_hash([
10212 var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
10214 var ASSIGNMENT = (function(a, ret, i){
10215 while (i < a.length) {
10216 ret[a[i]] = a[i].substr(0, a[i].length - 1);
10221 ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
10226 var PRECEDENCE = (function(a, ret){
10227 for (var i = 0, n = 1; i < a.length; ++i, ++n) {
10229 for (var j = 0; j < b.length; ++j) {
10241 ["==", "===", "!=", "!=="],
10242 ["<", ">", "<=", ">=", "in", "instanceof"],
10243 [">>", "<<", ">>>"],
10250 var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
10252 var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
10254 /* -----[ Parser ]----- */
10256 function NodeWithToken(str, start, end) {
10258 this.start = start;
10262 NodeWithToken.prototype.toString = function() { return this.name; };
10264 function parse($TEXT, exigent_mode, embed_tokens) {
10267 input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
10272 in_directives : true,
10279 function is(type, value) {
10280 return is_token(S.token, type, value);
10283 function peek() { return S.peeked || (S.peeked = S.input()); };
10288 S.token = S.peeked;
10291 S.token = S.input();
10293 S.in_directives = S.in_directives && (
10294 S.token.type == "string" || is("punc", ";")
10303 function croak(msg, line, col, pos) {
10304 var ctx = S.input.context();
10306 line != null ? line : ctx.tokline,
10307 col != null ? col : ctx.tokcol,
10308 pos != null ? pos : ctx.tokpos);
10311 function token_error(token, msg) {
10312 croak(msg, token.line, token.col);
10315 function unexpected(token) {
10318 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
10321 function expect_token(type, val) {
10322 if (is(type, val)) {
10325 token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
10328 function expect(punc) { return expect_token("punc", punc); };
10330 function can_insert_semicolon() {
10331 return !exigent_mode && (
10332 S.token.nlb || is("eof") || is("punc", "}")
10336 function semicolon() {
10337 if (is("punc", ";")) next();
10338 else if (!can_insert_semicolon()) unexpected();
10342 return slice(arguments);
10345 function parenthesised() {
10347 var ex = expression();
10352 function add_tokens(str, start, end) {
10353 return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
10356 function maybe_embed_tokens(parser) {
10357 if (embed_tokens) return function() {
10358 var start = S.token;
10359 var ast = parser.apply(this, arguments);
10360 ast[0] = add_tokens(ast[0], start, prev());
10363 else return parser;
10366 var statement = maybe_embed_tokens(function() {
10367 if (is("operator", "/") || is("operator", "/=")) {
10369 S.token = S.input(S.token.value.substr(1)); // force regexp
10371 switch (S.token.type) {
10373 var dir = S.in_directives, stat = simple_statement();
10374 if (dir && stat[1][0] == "string" && !is("punc", ","))
10375 return as("directive", stat[1][1]);
10381 return simple_statement();
10384 return is_token(peek(), "punc", ":")
10385 ? labeled_statement(prog1(S.token.value, next, next))
10386 : simple_statement();
10389 switch (S.token.value) {
10391 return as("block", block_());
10394 return simple_statement();
10397 return as("block");
10403 switch (prog1(S.token.value, next)) {
10405 return break_cont("break");
10408 return break_cont("continue");
10412 return as("debugger");
10415 return (function(body){
10416 expect_token("keyword", "while");
10417 return as("do", prog1(parenthesised, semicolon), body);
10418 })(in_loop(statement));
10424 return function_(true);
10430 if (S.in_function == 0)
10431 croak("'return' outside of function");
10432 return as("return",
10435 : can_insert_semicolon()
10437 : prog1(expression, semicolon));
10440 return as("switch", parenthesised(), switch_block_());
10444 croak("Illegal newline after 'throw'");
10445 return as("throw", prog1(expression, semicolon));
10451 return prog1(var_, semicolon);
10454 return prog1(const_, semicolon);
10457 return as("while", parenthesised(), in_loop(statement));
10460 return as("with", parenthesised(), statement());
10468 function labeled_statement(label) {
10469 S.labels.push(label);
10470 var start = S.token, stat = statement();
10471 if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
10474 return as("label", label, stat);
10477 function simple_statement() {
10478 return as("stat", prog1(expression, semicolon));
10481 function break_cont(type) {
10483 if (!can_insert_semicolon()) {
10484 name = is("name") ? S.token.value : null;
10486 if (name != null) {
10488 if (!member(name, S.labels))
10489 croak("Label " + name + " without matching loop or statement");
10491 else if (S.in_loop == 0)
10492 croak(type + " not inside a loop or switch");
10494 return as(type, name);
10500 if (!is("punc", ";")) {
10501 init = is("keyword", "var")
10502 ? (next(), var_(true))
10503 : expression(true, true);
10504 if (is("operator", "in")) {
10505 if (init[0] == "var" && init[1].length > 1)
10506 croak("Only one variable declaration allowed in for..in loop");
10507 return for_in(init);
10510 return regular_for(init);
10513 function regular_for(init) {
10515 var test = is("punc", ";") ? null : expression();
10517 var step = is("punc", ")") ? null : expression();
10519 return as("for", init, test, step, in_loop(statement));
10522 function for_in(init) {
10523 var lhs = init[0] == "var" ? as("name", init[1][0]) : init;
10525 var obj = expression();
10527 return as("for-in", init, lhs, obj, in_loop(statement));
10530 var function_ = function(in_statement) {
10531 var name = is("name") ? prog1(S.token.value, next) : null;
10532 if (in_statement && !name)
10535 return as(in_statement ? "defun" : "function",
10538 (function(first, a){
10539 while (!is("punc", ")")) {
10540 if (first) first = false; else expect(",");
10541 if (!is("name")) unexpected();
10542 a.push(S.token.value);
10551 var loop = S.in_loop;
10552 S.in_directives = true;
10562 var cond = parenthesised(), body = statement(), belse;
10563 if (is("keyword", "else")) {
10565 belse = statement();
10567 return as("if", cond, body, belse);
10570 function block_() {
10573 while (!is("punc", "}")) {
10574 if (is("eof")) unexpected();
10575 a.push(statement());
10581 var switch_block_ = curry(in_loop, function(){
10583 var a = [], cur = null;
10584 while (!is("punc", "}")) {
10585 if (is("eof")) unexpected();
10586 if (is("keyword", "case")) {
10589 a.push([ expression(), cur ]);
10592 else if (is("keyword", "default")) {
10596 a.push([ null, cur ]);
10599 if (!cur) unexpected();
10600 cur.push(statement());
10608 var body = block_(), bcatch, bfinally;
10609 if (is("keyword", "catch")) {
10613 croak("Name expected");
10614 var name = S.token.value;
10617 bcatch = [ name, block_() ];
10619 if (is("keyword", "finally")) {
10621 bfinally = block_();
10623 if (!bcatch && !bfinally)
10624 croak("Missing catch/finally blocks");
10625 return as("try", body, bcatch, bfinally);
10628 function vardefs(no_in) {
10633 var name = S.token.value;
10635 if (is("operator", "=")) {
10637 a.push([ name, expression(false, no_in) ]);
10641 if (!is("punc", ","))
10648 function var_(no_in) {
10649 return as("var", vardefs(no_in));
10652 function const_() {
10653 return as("const", vardefs());
10657 var newexp = expr_atom(false), args;
10658 if (is("punc", "(")) {
10660 args = expr_list(")");
10664 return subscripts(as("new", newexp, args), true);
10667 var expr_atom = maybe_embed_tokens(function(allow_calls) {
10668 if (is("operator", "new")) {
10673 switch (S.token.value) {
10676 return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
10679 return subscripts(array_(), allow_calls);
10682 return subscripts(object_(), allow_calls);
10686 if (is("keyword", "function")) {
10688 return subscripts(function_(false), allow_calls);
10690 if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
10691 var atom = S.token.type == "regexp"
10692 ? as("regexp", S.token.value[0], S.token.value[1])
10693 : as(S.token.type, S.token.value);
10694 return subscripts(prog1(atom, next), allow_calls);
10699 function expr_list(closing, allow_trailing_comma, allow_empty) {
10700 var first = true, a = [];
10701 while (!is("punc", closing)) {
10702 if (first) first = false; else expect(",");
10703 if (allow_trailing_comma && is("punc", closing)) break;
10704 if (is("punc", ",") && allow_empty) {
10705 a.push([ "atom", "undefined" ]);
10707 a.push(expression(false));
10714 function array_() {
10715 return as("array", expr_list("]", !exigent_mode, true));
10718 function object_() {
10719 var first = true, a = [];
10720 while (!is("punc", "}")) {
10721 if (first) first = false; else expect(",");
10722 if (!exigent_mode && is("punc", "}"))
10723 // allow trailing comma
10725 var type = S.token.type;
10726 var name = as_property_name();
10727 if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
10728 a.push([ as_name(), function_(false), name ]);
10731 a.push([ name, expression(false) ]);
10735 return as("object", a);
10738 function as_property_name() {
10739 switch (S.token.type) {
10742 return prog1(S.token.value, next);
10747 function as_name() {
10748 switch (S.token.type) {
10753 return prog1(S.token.value, next);
10759 function subscripts(expr, allow_calls) {
10760 if (is("punc", ".")) {
10762 return subscripts(as("dot", expr, as_name()), allow_calls);
10764 if (is("punc", "[")) {
10766 return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
10768 if (allow_calls && is("punc", "(")) {
10770 return subscripts(as("call", expr, expr_list(")")), true);
10775 function maybe_unary(allow_calls) {
10776 if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
10777 return make_unary("unary-prefix",
10778 prog1(S.token.value, next),
10779 maybe_unary(allow_calls));
10781 var val = expr_atom(allow_calls);
10782 while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) {
10783 val = make_unary("unary-postfix", S.token.value, val);
10789 function make_unary(tag, op, expr) {
10790 if ((op == "++" || op == "--") && !is_assignable(expr))
10791 croak("Invalid use of " + op + " operator");
10792 return as(tag, op, expr);
10795 function expr_op(left, min_prec, no_in) {
10796 var op = is("operator") ? S.token.value : null;
10797 if (op && op == "in" && no_in) op = null;
10798 var prec = op != null ? PRECEDENCE[op] : null;
10799 if (prec != null && prec > min_prec) {
10801 var right = expr_op(maybe_unary(true), prec, no_in);
10802 return expr_op(as("binary", op, left, right), min_prec, no_in);
10807 function expr_ops(no_in) {
10808 return expr_op(maybe_unary(true), 0, no_in);
10811 function maybe_conditional(no_in) {
10812 var expr = expr_ops(no_in);
10813 if (is("operator", "?")) {
10815 var yes = expression(false);
10817 return as("conditional", expr, yes, expression(false, no_in));
10822 function is_assignable(expr) {
10823 if (!exigent_mode) return true;
10824 switch (expr[0]+"") {
10831 return expr[1] != "this";
10835 function maybe_assign(no_in) {
10836 var left = maybe_conditional(no_in), val = S.token.value;
10837 if (is("operator") && HOP(ASSIGNMENT, val)) {
10838 if (is_assignable(left)) {
10840 return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));
10842 croak("Invalid assignment");
10847 var expression = maybe_embed_tokens(function(commas, no_in) {
10848 if (arguments.length == 0)
10850 var expr = maybe_assign(no_in);
10851 if (commas && is("punc", ",")) {
10853 return as("seq", expr, expression(true, no_in));
10858 function in_loop(cont) {
10867 return as("toplevel", (function(a){
10869 a.push(statement());
10875 /* -----[ Utilities ]----- */
10877 function curry(f) {
10878 var args = slice(arguments, 1);
10879 return function() { return f.apply(this, args.concat(slice(arguments))); };
10882 function prog1(ret) {
10883 if (ret instanceof Function)
10885 for (var i = 1, n = arguments.length; --n > 0; ++i)
10890 function array_to_hash(a) {
10892 for (var i = 0; i < a.length; ++i)
10897 function slice(a, start) {
10898 return Array.prototype.slice.call(a, start || 0);
10901 function characters(str) {
10902 return str.split("");
10905 function member(name, array) {
10906 for (var i = array.length; --i >= 0;)
10907 if (array[i] == name)
10912 function HOP(obj, prop) {
10913 return Object.prototype.hasOwnProperty.call(obj, prop);
10916 var warn = function() {};
10918 /* -----[ Exports ]----- */
10920 exports.tokenizer = tokenizer;
10921 exports.parse = parse;
10922 exports.slice = slice;
10923 exports.curry = curry;
10924 exports.member = member;
10925 exports.array_to_hash = array_to_hash;
10926 exports.PRECEDENCE = PRECEDENCE;
10927 exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
10928 exports.RESERVED_WORDS = RESERVED_WORDS;
10929 exports.KEYWORDS = KEYWORDS;
10930 exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
10931 exports.OPERATORS = OPERATORS;
10932 exports.is_alphanumeric_char = is_alphanumeric_char;
10933 exports.is_identifier_start = is_identifier_start;
10934 exports.is_identifier_char = is_identifier_char;
10935 exports.set_logger = function(logger) {
10939 // Local variables:
10940 // js-indent-level: 4
10942 });define('uglifyjs/squeeze-more', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
10943 var jsp = require("./parse-js"),
10944 pro = require("./process"),
10946 member = jsp.member,
10949 PRECEDENCE = jsp.PRECEDENCE,
10950 OPERATORS = jsp.OPERATORS;
10952 function ast_squeeze_more(ast) {
10953 var w = pro.ast_walker(), walk = w.walk, scope;
10954 function with_scope(s, cont) {
10955 var save = scope, ret;
10961 function _lambda(name, args, body) {
10962 return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
10964 return w.with_walkers({
10965 "toplevel": function(body) {
10966 return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
10968 "function": _lambda,
10970 "new": function(ctor, args) {
10971 if (ctor[0] == "name") {
10972 if (ctor[1] == "Array" && !scope.has("Array")) {
10973 if (args.length != 1) {
10974 return [ "array", args ];
10976 return walk([ "call", [ "name", "Array" ], args ]);
10978 } else if (ctor[1] == "Object" && !scope.has("Object")) {
10979 if (!args.length) {
10980 return [ "object", [] ];
10982 return walk([ "call", [ "name", "Object" ], args ]);
10984 } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) {
10985 return walk([ "call", [ "name", ctor[1] ], args]);
10989 "call": function(expr, args) {
10990 if (expr[0] == "dot" && expr[1][0] == "string" && args.length == 1
10991 && (args[0][1] > 0 && expr[2] == "substring" || expr[2] == "substr")) {
10992 return [ "call", [ "dot", expr[1], "slice"], args];
10994 if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
10995 // foo.toString() ==> foo+""
10996 if (expr[1][0] == "string") return expr[1];
10997 return [ "binary", "+", expr[1], [ "string", "" ]];
10999 if (expr[0] == "name") {
11000 if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
11001 return [ "array", args ];
11003 if (expr[1] == "Object" && !args.length && !scope.has("Object")) {
11004 return [ "object", [] ];
11006 if (expr[1] == "String" && !scope.has("String")) {
11007 return [ "binary", "+", args[0], [ "string", "" ]];
11012 return walk(pro.ast_add_scope(ast));
11016 exports.ast_squeeze_more = ast_squeeze_more;
11018 // Local variables:
11019 // js-indent-level: 4
11022 define('uglifyjs/process', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
11023 /***********************************************************************
11025 A JavaScript tokenizer / parser / beautifier / compressor.
11027 This version is suitable for Node.js. With minimal changes (the
11028 exports stuff) it should work on any JS platform.
11030 This file implements some AST processors. They work on data built
11033 Exported functions:
11035 - ast_mangle(ast, options) -- mangles the variable/function names
11036 in the AST. Returns an AST.
11038 - ast_squeeze(ast) -- employs various optimizations to make the
11039 final generated code even smaller. Returns an AST.
11041 - gen_code(ast, options) -- generates JS code from the AST. Pass
11042 true (or an object, see the code for some options) as second
11043 argument to get "pretty" (indented) code.
11045 -------------------------------- (C) ---------------------------------
11047 Author: Mihai Bazon
11048 <mihai.bazon@gmail.com>
11049 http://mihai.bazon.net/blog
11051 Distributed under the BSD license:
11053 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
11055 Redistribution and use in source and binary forms, with or without
11056 modification, are permitted provided that the following conditions
11059 * Redistributions of source code must retain the above
11060 copyright notice, this list of conditions and the following
11063 * Redistributions in binary form must reproduce the above
11064 copyright notice, this list of conditions and the following
11065 disclaimer in the documentation and/or other materials
11066 provided with the distribution.
11068 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
11069 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
11070 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
11071 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
11072 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
11073 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
11074 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
11075 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11076 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
11077 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
11078 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
11081 ***********************************************************************/
11083 var jsp = require("./parse-js"),
11086 member = jsp.member,
11087 is_identifier_char = jsp.is_identifier_char,
11088 PRECEDENCE = jsp.PRECEDENCE,
11089 OPERATORS = jsp.OPERATORS;
11091 /* -----[ helper for AST traversal ]----- */
11093 function ast_walker() {
11094 function _vardefs(defs) {
11095 return [ this[0], MAP(defs, function(def){
11096 var a = [ def[0] ];
11097 if (def.length > 1)
11098 a[1] = walk(def[1]);
11102 function _block(statements) {
11103 var out = [ this[0] ];
11104 if (statements != null)
11105 out.push(MAP(statements, walk));
11109 "string": function(str) {
11110 return [ this[0], str ];
11112 "num": function(num) {
11113 return [ this[0], num ];
11115 "name": function(name) {
11116 return [ this[0], name ];
11118 "toplevel": function(statements) {
11119 return [ this[0], MAP(statements, walk) ];
11125 "try": function(t, c, f) {
11129 c != null ? [ c[0], MAP(c[1], walk) ] : null,
11130 f != null ? MAP(f, walk) : null
11133 "throw": function(expr) {
11134 return [ this[0], walk(expr) ];
11136 "new": function(ctor, args) {
11137 return [ this[0], walk(ctor), MAP(args, walk) ];
11139 "switch": function(expr, body) {
11140 return [ this[0], walk(expr), MAP(body, function(branch){
11141 return [ branch[0] ? walk(branch[0]) : null,
11142 MAP(branch[1], walk) ];
11145 "break": function(label) {
11146 return [ this[0], label ];
11148 "continue": function(label) {
11149 return [ this[0], label ];
11151 "conditional": function(cond, t, e) {
11152 return [ this[0], walk(cond), walk(t), walk(e) ];
11154 "assign": function(op, lvalue, rvalue) {
11155 return [ this[0], op, walk(lvalue), walk(rvalue) ];
11157 "dot": function(expr) {
11158 return [ this[0], walk(expr) ].concat(slice(arguments, 1));
11160 "call": function(expr, args) {
11161 return [ this[0], walk(expr), MAP(args, walk) ];
11163 "function": function(name, args, body) {
11164 return [ this[0], name, args.slice(), MAP(body, walk) ];
11166 "debugger": function() {
11167 return [ this[0] ];
11169 "defun": function(name, args, body) {
11170 return [ this[0], name, args.slice(), MAP(body, walk) ];
11172 "if": function(conditional, t, e) {
11173 return [ this[0], walk(conditional), walk(t), walk(e) ];
11175 "for": function(init, cond, step, block) {
11176 return [ this[0], walk(init), walk(cond), walk(step), walk(block) ];
11178 "for-in": function(vvar, key, hash, block) {
11179 return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ];
11181 "while": function(cond, block) {
11182 return [ this[0], walk(cond), walk(block) ];
11184 "do": function(cond, block) {
11185 return [ this[0], walk(cond), walk(block) ];
11187 "return": function(expr) {
11188 return [ this[0], walk(expr) ];
11190 "binary": function(op, left, right) {
11191 return [ this[0], op, walk(left), walk(right) ];
11193 "unary-prefix": function(op, expr) {
11194 return [ this[0], op, walk(expr) ];
11196 "unary-postfix": function(op, expr) {
11197 return [ this[0], op, walk(expr) ];
11199 "sub": function(expr, subscript) {
11200 return [ this[0], walk(expr), walk(subscript) ];
11202 "object": function(props) {
11203 return [ this[0], MAP(props, function(p){
11204 return p.length == 2
11205 ? [ p[0], walk(p[1]) ]
11206 : [ p[0], walk(p[1]), p[2] ]; // get/set-ter
11209 "regexp": function(rx, mods) {
11210 return [ this[0], rx, mods ];
11212 "array": function(elements) {
11213 return [ this[0], MAP(elements, walk) ];
11215 "stat": function(stat) {
11216 return [ this[0], walk(stat) ];
11218 "seq": function() {
11219 return [ this[0] ].concat(MAP(slice(arguments), walk));
11221 "label": function(name, block) {
11222 return [ this[0], name, walk(block) ];
11224 "with": function(expr, block) {
11225 return [ this[0], walk(expr), walk(block) ];
11227 "atom": function(name) {
11228 return [ this[0], name ];
11230 "directive": function(dir) {
11231 return [ this[0], dir ];
11237 function walk(ast) {
11243 var gen = user[type];
11245 var ret = gen.apply(ast, ast.slice(1));
11249 gen = walkers[type];
11250 return gen.apply(ast, ast.slice(1));
11256 function dive(ast) {
11261 return walkers[ast[0]].apply(ast, ast.slice(1));
11267 function with_walkers(walkers, cont){
11269 for (i in walkers) if (HOP(walkers, i)) {
11271 user[i] = walkers[i];
11274 for (i in save) if (HOP(save, i)) {
11275 if (!save[i]) delete user[i];
11276 else user[i] = save[i];
11284 with_walkers: with_walkers,
11285 parent: function() {
11286 return stack[stack.length - 2]; // last one is current node
11288 stack: function() {
11294 /* -----[ Scope and mangling ]----- */
11296 function Scope(parent) {
11297 this.names = {}; // names defined in this scope
11298 this.mangled = {}; // mangled names (orig.name => mangled)
11299 this.rev_mangled = {}; // reverse lookup (mangled => orig.name)
11300 this.cname = -1; // current mangled name
11301 this.refs = {}; // names referenced from this scope
11302 this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes
11303 this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes
11304 this.directives = []; // directives activated from this scope
11305 this.parent = parent; // parent scope
11306 this.children = []; // sub-scopes
11308 this.level = parent.level + 1;
11309 parent.children.push(this);
11315 function base54_digits() {
11316 if (typeof DIGITS_OVERRIDE_FOR_TESTING != "undefined")
11317 return DIGITS_OVERRIDE_FOR_TESTING;
11319 return "etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984";
11322 var base54 = (function(){
11323 var DIGITS = base54_digits();
11324 return function(num) {
11325 var ret = "", base = 54;
11327 ret += DIGITS.charAt(num % base);
11328 num = Math.floor(num / base);
11335 Scope.prototype = {
11336 has: function(name) {
11337 for (var s = this; s; s = s.parent)
11338 if (HOP(s.names, name))
11341 has_mangled: function(mname) {
11342 for (var s = this; s; s = s.parent)
11343 if (HOP(s.rev_mangled, mname))
11346 toJSON: function() {
11349 uses_eval: this.uses_eval,
11350 uses_with: this.uses_with
11354 next_mangled: function() {
11355 // we must be careful that the new mangled name:
11357 // 1. doesn't shadow a mangled name from a parent
11358 // scope, unless we don't reference the original
11359 // name from this scope OR from any sub-scopes!
11360 // This will get slow.
11362 // 2. doesn't shadow an original name from a parent
11363 // scope, in the event that the name is not mangled
11364 // in the parent scope and we reference that name
11365 // here OR IN ANY SUBSCOPES!
11367 // 3. doesn't shadow a name that is referenced but not
11368 // defined (possibly global defined elsewhere).
11370 var m = base54(++this.cname), prior;
11373 prior = this.has_mangled(m);
11374 if (prior && this.refs[prior.rev_mangled[m]] === prior)
11378 prior = this.has(m);
11379 if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m))
11383 if (HOP(this.refs, m) && this.refs[m] == null)
11386 // I got "do" once. :-/
11387 if (!is_identifier(m))
11393 set_mangle: function(name, m) {
11394 this.rev_mangled[m] = name;
11395 return this.mangled[name] = m;
11397 get_mangled: function(name, newMangle) {
11398 if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use
11399 var s = this.has(name);
11400 if (!s) return name; // not in visible scope, no mangle
11401 if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope
11402 if (!newMangle) return name; // not found and no mangling requested
11403 return s.set_mangle(name, s.next_mangled());
11405 references: function(name) {
11406 return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name];
11408 define: function(name, type) {
11409 if (name != null) {
11410 if (type == "var" || !HOP(this.names, name))
11411 this.names[name] = type || "var";
11415 active_directive: function(dir) {
11416 return member(dir, this.directives) || this.parent && this.parent.active_directive(dir);
11420 function ast_add_scope(ast) {
11422 var current_scope = null;
11423 var w = ast_walker(), walk = w.walk;
11424 var having_eval = [];
11426 function with_new_scope(cont) {
11427 current_scope = new Scope(current_scope);
11428 current_scope.labels = new Scope();
11429 var ret = current_scope.body = cont();
11430 ret.scope = current_scope;
11431 current_scope = current_scope.parent;
11435 function define(name, type) {
11436 return current_scope.define(name, type);
11439 function reference(name) {
11440 current_scope.refs[name] = true;
11443 function _lambda(name, args, body) {
11444 var is_defun = this[0] == "defun";
11445 return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){
11446 if (!is_defun) define(name, "lambda");
11447 MAP(args, function(name){ define(name, "arg") });
11448 return MAP(body, walk);
11452 function _vardefs(type) {
11453 return function(defs) {
11454 MAP(defs, function(d){
11455 define(d[0], type);
11456 if (d[1]) reference(d[0]);
11461 function _breacont(label) {
11463 current_scope.labels.refs[label] = true;
11466 return with_new_scope(function(){
11468 var ret = w.with_walkers({
11469 "function": _lambda,
11471 "label": function(name, stat) { current_scope.labels.define(name) },
11472 "break": _breacont,
11473 "continue": _breacont,
11474 "with": function(expr, block) {
11475 for (var s = current_scope; s; s = s.parent)
11476 s.uses_with = true;
11478 "var": _vardefs("var"),
11479 "const": _vardefs("const"),
11480 "try": function(t, c, f) {
11481 if (c != null) return [
11484 [ define(c[0], "catch"), MAP(c[1], walk) ],
11485 f != null ? MAP(f, walk) : null
11488 "name": function(name) {
11489 if (name == "eval")
11490 having_eval.push(current_scope);
11497 // the reason why we need an additional pass here is
11498 // that names can be used prior to their definition.
11500 // scopes where eval was detected and their parents
11501 // are marked with uses_eval, unless they define the
11503 MAP(having_eval, function(scope){
11504 if (!scope.has("eval")) while (scope) {
11505 scope.uses_eval = true;
11506 scope = scope.parent;
11510 // for referenced names it might be useful to know
11511 // their origin scope. current_scope here is the
11513 function fixrefs(scope, i) {
11514 // do children first; order shouldn't matter
11515 for (i = scope.children.length; --i >= 0;)
11516 fixrefs(scope.children[i]);
11517 for (i in scope.refs) if (HOP(scope.refs, i)) {
11518 // find origin scope and propagate the reference to origin
11519 for (var origin = scope.has(i), s = scope; s; s = s.parent) {
11520 s.refs[i] = origin;
11521 if (s === origin) break;
11525 fixrefs(current_scope);
11532 /* -----[ mangle names ]----- */
11534 function ast_mangle(ast, options) {
11535 var w = ast_walker(), walk = w.walk, scope;
11536 options = defaults(options, {
11541 no_functions : false
11544 function get_mangled(name, newMangle) {
11545 if (!options.mangle) return name;
11546 if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel
11547 if (options.except && member(name, options.except))
11549 if (options.no_functions && HOP(scope.names, name) &&
11550 (scope.names[name] == 'defun' || scope.names[name] == 'lambda'))
11552 return scope.get_mangled(name, newMangle);
11555 function get_define(name) {
11556 if (options.defines) {
11557 // we always lookup a defined symbol for the current scope FIRST, so declared
11558 // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value
11559 if (!scope.has(name)) {
11560 if (HOP(options.defines, name)) {
11561 return options.defines[name];
11568 function _lambda(name, args, body) {
11569 if (!options.no_functions && options.mangle) {
11570 var is_defun = this[0] == "defun", extra;
11572 if (is_defun) name = get_mangled(name);
11573 else if (body.scope.references(name)) {
11575 if (!(scope.uses_eval || scope.uses_with))
11576 name = extra[name] = scope.next_mangled();
11578 extra[name] = name;
11583 body = with_scope(body.scope, function(){
11584 args = MAP(args, function(name){ return get_mangled(name) });
11585 return MAP(body, walk);
11587 return [ this[0], name, args, body ];
11590 function with_scope(s, cont, extra) {
11591 var _scope = scope;
11593 if (extra) for (var i in extra) if (HOP(extra, i)) {
11594 s.set_mangle(i, extra[i]);
11596 for (var i in s.names) if (HOP(s.names, i)) {
11597 get_mangled(i, true);
11605 function _vardefs(defs) {
11606 return [ this[0], MAP(defs, function(d){
11607 return [ get_mangled(d[0]), walk(d[1]) ];
11611 function _breacont(label) {
11612 if (label) return [ this[0], scope.labels.get_mangled(label) ];
11615 return w.with_walkers({
11616 "function": _lambda,
11617 "defun": function() {
11618 // move function declarations to the top when
11619 // they are not in some block.
11620 var ast = _lambda.apply(this, arguments);
11621 switch (w.parent()[0]) {
11625 return MAP.at_top(ast);
11629 "label": function(label, stat) {
11630 if (scope.labels.refs[label]) return [
11632 scope.labels.get_mangled(label, true),
11637 "break": _breacont,
11638 "continue": _breacont,
11641 "name": function(name) {
11642 return get_define(name) || [ this[0], get_mangled(name) ];
11644 "try": function(t, c, f) {
11647 c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null,
11648 f != null ? MAP(f, walk) : null ];
11650 "toplevel": function(body) {
11652 return with_scope(self.scope, function(){
11653 return [ self[0], MAP(body, walk) ];
11656 "directive": function() {
11657 return MAP.at_top(this);
11660 return walk(ast_add_scope(ast));
11665 - compress foo["bar"] into foo.bar,
11666 - remove block brackets {} where possible
11667 - join consecutive var declarations
11668 - various optimizations for IFs:
11669 - if (cond) foo(); else bar(); ==> cond?foo():bar();
11670 - if (cond) foo(); ==> cond&&foo();
11671 - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); // also for throw
11672 - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
11675 var warn = function(){};
11677 function best_of(ast1, ast2) {
11678 return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
11681 function last_stat(b) {
11682 if (b[0] == "block" && b[1] && b[1].length > 0)
11683 return b[1][b[1].length - 1];
11687 function aborts(t) {
11688 if (t) switch (last_stat(t)[0]) {
11697 function boolean_expr(expr) {
11698 return ( (expr[0] == "unary-prefix"
11699 && member(expr[1], [ "!", "delete" ])) ||
11701 (expr[0] == "binary"
11702 && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) ||
11704 (expr[0] == "binary"
11705 && member(expr[1], [ "&&", "||" ])
11706 && boolean_expr(expr[2])
11707 && boolean_expr(expr[3])) ||
11709 (expr[0] == "conditional"
11710 && boolean_expr(expr[2])
11711 && boolean_expr(expr[3])) ||
11713 (expr[0] == "assign"
11714 && expr[1] === true
11715 && boolean_expr(expr[3])) ||
11718 && boolean_expr(expr[expr.length - 1]))
11722 function empty(b) {
11723 return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
11726 function is_string(node) {
11727 return (node[0] == "string" ||
11728 node[0] == "unary-prefix" && node[1] == "typeof" ||
11729 node[0] == "binary" && node[1] == "+" &&
11730 (is_string(node[2]) || is_string(node[3])));
11733 var when_constant = (function(){
11735 var $NOT_CONSTANT = {};
11737 // this can only evaluate constant expressions. If it finds anything
11738 // not constant, it throws $NOT_CONSTANT.
11739 function evaluate(expr) {
11747 case "true": return true;
11748 case "false": return false;
11749 case "null": return null;
11752 case "unary-prefix":
11754 case "!": return !evaluate(expr[2]);
11755 case "typeof": return typeof evaluate(expr[2]);
11756 case "~": return ~evaluate(expr[2]);
11757 case "-": return -evaluate(expr[2]);
11758 case "+": return +evaluate(expr[2]);
11762 var left = expr[2], right = expr[3];
11764 case "&&" : return evaluate(left) && evaluate(right);
11765 case "||" : return evaluate(left) || evaluate(right);
11766 case "|" : return evaluate(left) | evaluate(right);
11767 case "&" : return evaluate(left) & evaluate(right);
11768 case "^" : return evaluate(left) ^ evaluate(right);
11769 case "+" : return evaluate(left) + evaluate(right);
11770 case "*" : return evaluate(left) * evaluate(right);
11771 case "/" : return evaluate(left) / evaluate(right);
11772 case "%" : return evaluate(left) % evaluate(right);
11773 case "-" : return evaluate(left) - evaluate(right);
11774 case "<<" : return evaluate(left) << evaluate(right);
11775 case ">>" : return evaluate(left) >> evaluate(right);
11776 case ">>>" : return evaluate(left) >>> evaluate(right);
11777 case "==" : return evaluate(left) == evaluate(right);
11778 case "===" : return evaluate(left) === evaluate(right);
11779 case "!=" : return evaluate(left) != evaluate(right);
11780 case "!==" : return evaluate(left) !== evaluate(right);
11781 case "<" : return evaluate(left) < evaluate(right);
11782 case "<=" : return evaluate(left) <= evaluate(right);
11783 case ">" : return evaluate(left) > evaluate(right);
11784 case ">=" : return evaluate(left) >= evaluate(right);
11785 case "in" : return evaluate(left) in evaluate(right);
11786 case "instanceof" : return evaluate(left) instanceof evaluate(right);
11789 throw $NOT_CONSTANT;
11792 return function(expr, yes, no) {
11794 var val = evaluate(expr), ast;
11795 switch (typeof val) {
11796 case "string": ast = [ "string", val ]; break;
11797 case "number": ast = [ "num", val ]; break;
11798 case "boolean": ast = [ "name", String(val) ]; break;
11800 if (val === null) { ast = [ "atom", "null" ]; break; }
11801 throw new Error("Can't handle constant of type: " + (typeof val));
11803 return yes.call(expr, ast, val);
11805 if (ex === $NOT_CONSTANT) {
11806 if (expr[0] == "binary"
11807 && (expr[1] == "===" || expr[1] == "!==")
11808 && ((is_string(expr[2]) && is_string(expr[3]))
11809 || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) {
11810 expr[1] = expr[1].substr(0, 2);
11812 else if (no && expr[0] == "binary"
11813 && (expr[1] == "||" || expr[1] == "&&")) {
11814 // the whole expression is not constant but the lval may be...
11816 var lval = evaluate(expr[2]);
11817 expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) ||
11818 (expr[1] == "||" && (lval ? lval : expr[3])) ||
11821 // IGNORE... lval is not constant
11824 return no ? no.call(expr, expr) : null;
11832 function warn_unreachable(ast) {
11834 warn("Dropping unreachable code: " + gen_code(ast, true));
11837 function prepare_ifs(ast) {
11838 var w = ast_walker(), walk = w.walk;
11839 // In this first pass, we rewrite ifs which abort with no else with an
11840 // if-else. For example:
11848 // is rewritten into:
11856 function redo_if(statements) {
11857 statements = MAP(statements, walk);
11859 for (var i = 0; i < statements.length; ++i) {
11860 var fi = statements[i];
11861 if (fi[0] != "if") continue;
11863 if (fi[3]) continue;
11866 if (!aborts(t)) continue;
11868 var conditional = walk(fi[1]);
11870 var e_body = redo_if(statements.slice(i + 1));
11871 var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ];
11873 return statements.slice(0, i).concat([ [
11875 conditional, // conditional
11884 function redo_if_lambda(name, args, body) {
11885 body = redo_if(body);
11886 return [ this[0], name, args, body ];
11889 function redo_if_block(statements) {
11890 return [ this[0], statements != null ? redo_if(statements) : null ];
11893 return w.with_walkers({
11894 "defun": redo_if_lambda,
11895 "function": redo_if_lambda,
11896 "block": redo_if_block,
11897 "splice": redo_if_block,
11898 "toplevel": function(statements) {
11899 return [ this[0], redo_if(statements) ];
11901 "try": function(t, c, f) {
11905 c != null ? [ c[0], redo_if(c[1]) ] : null,
11906 f != null ? redo_if(f) : null
11914 function for_side_effects(ast, handler) {
11915 var w = ast_walker(), walk = w.walk;
11916 var $stop = {}, $restart = {};
11917 function stop() { throw $stop };
11918 function restart() { throw $restart };
11919 function found(){ return handler.call(this, this, w, stop, restart) };
11920 function unary(op) {
11921 if (op == "++" || op == "--")
11922 return found.apply(this, arguments);
11924 function binary(op) {
11925 if (op == "&&" || op == "||")
11926 return found.apply(this, arguments);
11928 return w.with_walkers({
11944 "unary-prefix": unary,
11945 "unary-postfix": unary,
11946 "conditional": found,
11954 if (ex === $stop) break;
11955 if (ex === $restart) continue;
11961 function ast_lift_variables(ast) {
11962 var w = ast_walker(), walk = w.walk, scope;
11963 function do_body(body, env) {
11964 var _scope = scope;
11966 body = MAP(body, walk);
11967 var hash = {}, names = MAP(env.names, function(type, name){
11968 if (type != "var") return MAP.skip;
11969 if (!env.references(name)) return MAP.skip;
11973 if (names.length > 0) {
11974 // looking for assignments to any of these variables.
11975 // we can save considerable space by moving the definitions
11976 // in the var declaration.
11977 for_side_effects([ "block", body ], function(ast, walker, stop, restart) {
11978 if (ast[0] == "assign"
11980 && ast[2][0] == "name"
11981 && HOP(hash, ast[2][1])) {
11982 // insert the definition into the var declaration
11983 for (var i = names.length; --i >= 0;) {
11984 if (names[i][0] == ast[2][1]) {
11985 if (names[i][1]) // this name already defined, we must stop
11987 names[i][1] = ast[3]; // definition
11988 names.push(names.splice(i, 1)[0]);
11992 // remove this assignment from the AST.
11993 var p = walker.parent();
11994 if (p[0] == "seq") {
11996 a.unshift(0, p.length);
11997 p.splice.apply(p, a);
11999 else if (p[0] == "stat") {
12000 p.splice(0, p.length, "block"); // empty statement
12009 body.unshift([ "var", names ]);
12014 function _vardefs(defs) {
12016 for (var i = defs.length; --i >= 0;) {
12018 if (!d[1]) continue;
12019 d = [ "assign", true, [ "name", d[0] ], d[1] ];
12020 if (ret == null) ret = d;
12021 else ret = [ "seq", d, ret ];
12023 if (ret == null && w.parent()[0] != "for") {
12024 if (w.parent()[0] == "for-in")
12025 return [ "name", defs[0][0] ];
12028 return [ "stat", ret ];
12030 function _toplevel(body) {
12031 return [ this[0], do_body(body, this.scope) ];
12033 return w.with_walkers({
12034 "function": function(name, args, body){
12035 for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
12037 if (!body.scope.references(name)) name = null;
12038 return [ this[0], name, args, do_body(body, body.scope) ];
12040 "defun": function(name, args, body){
12041 if (!scope.references(name)) return MAP.skip;
12042 for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
12044 return [ this[0], name, args, do_body(body, body.scope) ];
12047 "toplevel": _toplevel
12049 return walk(ast_add_scope(ast));
12053 function ast_squeeze(ast, options) {
12054 ast = squeeze_1(ast, options);
12055 ast = squeeze_2(ast, options);
12059 function squeeze_1(ast, options) {
12060 options = defaults(options, {
12063 no_warnings : false,
12068 var w = ast_walker(), walk = w.walk, scope;
12070 function negate(c) {
12071 var not_c = [ "unary-prefix", "!", c ];
12073 case "unary-prefix":
12074 return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c;
12077 c[c.length - 1] = negate(c[c.length - 1]);
12079 case "conditional":
12080 return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]);
12082 var op = c[1], left = c[2], right = c[3];
12083 if (!options.keep_comps) switch (op) {
12084 case "<=" : return [ "binary", ">", left, right ];
12085 case "<" : return [ "binary", ">=", left, right ];
12086 case ">=" : return [ "binary", "<", left, right ];
12087 case ">" : return [ "binary", "<=", left, right ];
12090 case "==" : return [ "binary", "!=", left, right ];
12091 case "!=" : return [ "binary", "==", left, right ];
12092 case "===" : return [ "binary", "!==", left, right ];
12093 case "!==" : return [ "binary", "===", left, right ];
12094 case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]);
12095 case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]);
12102 function make_conditional(c, t, e) {
12103 var make_real_conditional = function() {
12104 if (c[0] == "unary-prefix" && c[1] == "!") {
12105 return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
12107 return e ? best_of(
12108 [ "conditional", c, t, e ],
12109 [ "conditional", negate(c), e, t ]
12110 ) : [ "binary", "&&", c, t ];
12113 // shortcut the conditional if the expression has a constant value
12114 return when_constant(c, function(ast, val){
12115 warn_unreachable(val ? e : t);
12116 return (val ? t : e);
12117 }, make_real_conditional);
12120 function rmblock(block) {
12121 if (block != null && block[0] == "block" && block[1]) {
12122 if (block[1].length == 1)
12123 block = block[1][0];
12124 else if (block[1].length == 0)
12125 block = [ "block" ];
12130 function _lambda(name, args, body) {
12131 return [ this[0], name, args, tighten(body, "lambda") ];
12134 // this function does a few things:
12135 // 1. discard useless blocks
12136 // 2. join consecutive var declarations
12137 // 3. remove obviously dead code
12138 // 4. transform consecutive statements using the comma operator
12139 // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... }
12140 function tighten(statements, block_type) {
12141 statements = MAP(statements, walk);
12143 statements = statements.reduce(function(a, stat){
12144 if (stat[0] == "block") {
12146 a.push.apply(a, stat[1]);
12154 statements = (function(a, prev){
12155 statements.forEach(function(cur){
12156 if (prev && ((cur[0] == "var" && prev[0] == "var") ||
12157 (cur[0] == "const" && prev[0] == "const"))) {
12158 prev[1] = prev[1].concat(cur[1]);
12167 if (options.dead_code) statements = (function(a, has_quit){
12168 statements.forEach(function(st){
12170 if (st[0] == "function" || st[0] == "defun") {
12173 else if (st[0] == "var" || st[0] == "const") {
12174 if (!options.no_warnings)
12175 warn("Variables declared in unreachable code");
12176 st[1] = MAP(st[1], function(def){
12177 if (def[1] && !options.no_warnings)
12178 warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]);
12183 else if (!options.no_warnings)
12184 warn_unreachable(st);
12188 if (member(st[0], [ "return", "throw", "break", "continue" ]))
12195 if (options.make_seqs) statements = (function(a, prev) {
12196 statements.forEach(function(cur){
12197 if (prev && prev[0] == "stat" && cur[0] == "stat") {
12198 prev[1] = [ "seq", prev[1], cur[1] ];
12205 && a[a.length-2][0] == "stat"
12206 && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw")
12207 && a[a.length-1][1])
12209 a.splice(a.length - 2, 2,
12210 [ a[a.length-1][0],
12211 [ "seq", a[a.length-2][1], a[a.length-1][1] ]]);
12216 // this increases jQuery by 1K. Probably not such a good idea after all..
12217 // part of this is done in prepare_ifs anyway.
12218 // if (block_type == "lambda") statements = (function(i, a, stat){
12219 // while (i < statements.length) {
12220 // stat = statements[i++];
12221 // if (stat[0] == "if" && !stat[3]) {
12222 // if (stat[2][0] == "return" && stat[2][1] == null) {
12223 // a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
12226 // var last = last_stat(stat[2]);
12227 // if (last[0] == "return" && last[1] == null) {
12228 // a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
12240 function make_if(c, t, e) {
12241 return when_constant(c, function(ast, val){
12244 warn_unreachable(e);
12245 return t || [ "block" ];
12248 warn_unreachable(t);
12249 return e || [ "block" ];
12252 return make_real_if(c, t, e);
12256 function abort_else(c, t, e) {
12257 var ret = [ [ "if", negate(c), e ] ];
12258 if (t[0] == "block") {
12259 if (t[1]) ret = ret.concat(t[1]);
12263 return walk([ "block", ret ]);
12266 function make_real_if(c, t, e) {
12271 if (empty(e) && empty(t))
12272 return [ "stat", c ];
12278 } else if (empty(e)) {
12281 // if we have both else and then, maybe it makes sense to switch them?
12283 var a = gen_code(c);
12285 var b = gen_code(n);
12286 if (b.length < a.length) {
12294 var ret = [ "if", c, t, e ];
12295 if (t[0] == "if" && empty(t[3]) && empty(e)) {
12296 ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ]));
12298 else if (t[0] == "stat") {
12300 if (e[0] == "stat")
12301 ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]);
12302 else if (aborts(e))
12303 ret = abort_else(c, t, e);
12306 ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]);
12309 else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) {
12310 ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]);
12312 else if (e && aborts(t)) {
12313 ret = [ [ "if", c, t ] ];
12314 if (e[0] == "block") {
12315 if (e[1]) ret = ret.concat(e[1]);
12320 ret = walk([ "block", ret ]);
12322 else if (t && aborts(e)) {
12323 ret = abort_else(c, t, e);
12328 function _do_while(cond, body) {
12329 return when_constant(cond, function(cond, val){
12331 warn_unreachable(body);
12332 return [ "block" ];
12334 return [ "for", null, null, null, walk(body) ];
12339 return w.with_walkers({
12340 "sub": function(expr, subscript) {
12341 if (subscript[0] == "string") {
12342 var name = subscript[1];
12343 if (is_identifier(name))
12344 return [ "dot", walk(expr), name ];
12345 else if (/^[1-9][0-9]*$/.test(name) || name === "0")
12346 return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ];
12350 "toplevel": function(body) {
12351 return [ "toplevel", tighten(body) ];
12353 "switch": function(expr, body) {
12354 var last = body.length - 1;
12355 return [ "switch", walk(expr), MAP(body, function(branch, i){
12356 var block = tighten(branch[1]);
12357 if (i == last && block.length > 0) {
12358 var node = block[block.length - 1];
12359 if (node[0] == "break" && !node[1])
12362 return [ branch[0] ? walk(branch[0]) : null, block ];
12365 "function": _lambda,
12367 "block": function(body) {
12368 if (body) return rmblock([ "block", tighten(body) ]);
12370 "binary": function(op, left, right) {
12371 return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){
12372 return best_of(walk(c), this);
12375 if(op != "==" && op != "!=") return;
12376 var l = walk(left), r = walk(right);
12377 if(l && l[0] == "unary-prefix" && l[1] == "!" && l[2][0] == "num")
12378 left = ['num', +!l[2][1]];
12379 else if (r && r[0] == "unary-prefix" && r[1] == "!" && r[2][0] == "num")
12380 right = ['num', +!r[2][1]];
12381 return ["binary", op, left, right];
12385 "conditional": function(c, t, e) {
12386 return make_conditional(walk(c), walk(t), walk(e));
12388 "try": function(t, c, f) {
12392 c != null ? [ c[0], tighten(c[1]) ] : null,
12393 f != null ? tighten(f) : null
12396 "unary-prefix": function(op, expr) {
12398 var ret = [ "unary-prefix", op, expr ];
12400 ret = best_of(ret, negate(expr));
12401 return when_constant(ret, function(ast, val){
12402 return walk(ast); // it's either true or false, so minifies to !0 or !1
12403 }, function() { return ret });
12405 "name": function(name) {
12407 case "true": return [ "unary-prefix", "!", [ "num", 0 ]];
12408 case "false": return [ "unary-prefix", "!", [ "num", 1 ]];
12411 "while": _do_while,
12412 "assign": function(op, lvalue, rvalue) {
12413 lvalue = walk(lvalue);
12414 rvalue = walk(rvalue);
12415 var okOps = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
12416 if (op === true && lvalue[0] === "name" && rvalue[0] === "binary" &&
12417 ~okOps.indexOf(rvalue[1]) && rvalue[2][0] === "name" &&
12418 rvalue[2][1] === lvalue[1]) {
12419 return [ this[0], rvalue[1], lvalue, rvalue[3] ]
12421 return [ this[0], op, lvalue, rvalue ];
12423 "call": function(expr, args) {
12425 if (options.unsafe && expr[0] == "dot" && expr[1][0] == "string" && expr[2] == "toString") {
12428 return [ this[0], expr, MAP(args, walk) ];
12430 "num": function (num) {
12431 if (!isFinite(num))
12432 return [ "binary", "/", num === 1 / 0
12433 ? [ "num", 1 ] : num === -1 / 0
12434 ? [ "unary-prefix", "-", [ "num", 1 ] ]
12435 : [ "num", 0 ], [ "num", 0 ] ];
12437 return [ this[0], num ];
12440 return walk(prepare_ifs(walk(prepare_ifs(ast))));
12444 function squeeze_2(ast, options) {
12445 var w = ast_walker(), walk = w.walk, scope;
12446 function with_scope(s, cont) {
12447 var save = scope, ret;
12453 function lambda(name, args, body) {
12454 return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
12456 return w.with_walkers({
12457 "directive": function(dir) {
12458 if (scope.active_directive(dir))
12459 return [ "block" ];
12460 scope.directives.push(dir);
12462 "toplevel": function(body) {
12463 return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
12465 "function": lambda,
12468 return walk(ast_add_scope(ast));
12472 /* -----[ re-generate code from the AST ]----- */
12474 var DOT_CALL_NO_PARENS = jsp.array_to_hash([
12486 function make_string(str, ascii_only) {
12487 var dq = 0, sq = 0;
12488 str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
12490 case "\\": return "\\\\";
12491 case "\b": return "\\b";
12492 case "\f": return "\\f";
12493 case "\n": return "\\n";
12494 case "\r": return "\\r";
12495 case "\u2028": return "\\u2028";
12496 case "\u2029": return "\\u2029";
12497 case '"': ++dq; return '"';
12498 case "'": ++sq; return "'";
12499 case "\0": return "\\0";
12503 if (ascii_only) str = to_ascii(str);
12504 if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
12505 else return '"' + str.replace(/\x22/g, '\\"') + '"';
12508 function to_ascii(str) {
12509 return str.replace(/[\u0080-\uffff]/g, function(ch) {
12510 var code = ch.charCodeAt(0).toString(16);
12511 while (code.length < 4) code = "0" + code;
12512 return "\\u" + code;
12516 var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]);
12518 function gen_code(ast, options) {
12519 options = defaults(options, {
12522 quote_keys : false,
12523 space_colon : false,
12525 ascii_only : false,
12526 inline_script: false
12528 var beautify = !!options.beautify;
12529 var indentation = 0,
12530 newline = beautify ? "\n" : "",
12531 space = beautify ? " " : "";
12533 function encode_string(str) {
12534 var ret = make_string(str, options.ascii_only);
12535 if (options.inline_script)
12536 ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
12540 function make_name(name) {
12541 name = name.toString();
12542 if (options.ascii_only)
12543 name = to_ascii(name);
12547 function indent(line) {
12551 line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line;
12555 function with_indent(cont, incr) {
12556 if (incr == null) incr = 1;
12557 indentation += incr;
12558 try { return cont.apply(null, slice(arguments, 1)); }
12559 finally { indentation -= incr; }
12562 function last_char(str) {
12563 str = str.toString();
12564 return str.charAt(str.length - 1);
12567 function first_char(str) {
12568 return str.toString().charAt(0);
12571 function add_spaces(a) {
12573 return a.join(" ");
12575 for (var i = 0; i < a.length; ++i) {
12576 var next = a[i + 1];
12579 ((is_identifier_char(last_char(a[i])) && (is_identifier_char(first_char(next))
12580 || first_char(next) == "\\")) ||
12581 (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString()) ||
12582 last_char(a[i]) == "/" && first_char(next) == "/"))) {
12589 function add_commas(a) {
12590 return a.join("," + space);
12593 function parenthesize(expr) {
12594 var gen = make(expr);
12595 for (var i = 1; i < arguments.length; ++i) {
12596 var el = arguments[i];
12597 if ((el instanceof Function && el(expr)) || expr[0] == el)
12598 return "(" + gen + ")";
12603 function best_of(a) {
12604 if (a.length == 1) {
12607 if (a.length == 2) {
12610 return a.length <= b.length ? a : b;
12612 return best_of([ a[0], best_of(a.slice(1)) ]);
12615 function needs_parens(expr) {
12616 if (expr[0] == "function" || expr[0] == "object") {
12617 // dot/call on a literal function requires the
12618 // function literal itself to be parenthesized
12619 // only if it's the first "thing" in a
12620 // statement. This means that the parent is
12621 // "stat", but it could also be a "seq" and
12622 // we're the first in this "seq" and the
12623 // parent is "stat", and so on. Messy stuff,
12624 // but it worths the trouble.
12625 var a = slice(w.stack()), self = a.pop(), p = a.pop();
12627 if (p[0] == "stat") return true;
12628 if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) ||
12629 ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) {
12637 return !HOP(DOT_CALL_NO_PARENS, expr[0]);
12640 function make_num(num) {
12641 var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
12642 if (Math.floor(num) === num) {
12644 a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
12645 "0" + num.toString(8)); // same.
12647 a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
12648 "-0" + (-num).toString(8)); // same.
12650 if ((m = /^(.*?)(0+)$/.exec(num))) {
12651 a.push(m[1] + "e" + m[2].length);
12653 } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
12654 a.push(m[2] + "e-" + (m[1].length + m[2].length),
12655 str.substr(str.indexOf(".")));
12660 var w = ast_walker();
12662 return w.with_walkers({
12663 "string": encode_string,
12666 "debugger": function(){ return "debugger;" },
12667 "toplevel": function(statements) {
12668 return make_block_statements(statements)
12669 .join(newline + newline);
12671 "splice": function(statements) {
12672 var parent = w.parent();
12673 if (HOP(SPLICE_NEEDS_BRACKETS, parent)) {
12674 // we need block brackets in this case
12675 return make_block.apply(this, arguments);
12677 return MAP(make_block_statements(statements, true),
12678 function(line, i) {
12679 // the first line is already indented
12680 return i > 0 ? indent(line) : line;
12684 "block": make_block,
12685 "var": function(defs) {
12686 return "var " + add_commas(MAP(defs, make_1vardef)) + ";";
12688 "const": function(defs) {
12689 return "const " + add_commas(MAP(defs, make_1vardef)) + ";";
12691 "try": function(tr, ca, fi) {
12692 var out = [ "try", make_block(tr) ];
12693 if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1]));
12694 if (fi) out.push("finally", make_block(fi));
12695 return add_spaces(out);
12697 "throw": function(expr) {
12698 return add_spaces([ "throw", make(expr) ]) + ";";
12700 "new": function(ctor, args) {
12701 args = args.length > 0 ? "(" + add_commas(MAP(args, function(expr){
12702 return parenthesize(expr, "seq");
12704 return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){
12705 var w = ast_walker(), has_call = {};
12708 "call": function() { throw has_call },
12709 "function": function() { return this }
12714 if (ex === has_call)
12720 "switch": function(expr, body) {
12721 return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]);
12723 "break": function(label) {
12726 out += " " + make_name(label);
12729 "continue": function(label) {
12730 var out = "continue";
12732 out += " " + make_name(label);
12735 "conditional": function(co, th, el) {
12736 return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?",
12737 parenthesize(th, "seq"), ":",
12738 parenthesize(el, "seq") ]);
12740 "assign": function(op, lvalue, rvalue) {
12741 if (op && op !== true) op += "=";
12743 return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]);
12745 "dot": function(expr) {
12746 var out = make(expr), i = 1;
12747 if (expr[0] == "num") {
12748 if (!/[a-f.]/i.test(out))
12750 } else if (expr[0] != "function" && needs_parens(expr))
12751 out = "(" + out + ")";
12752 while (i < arguments.length)
12753 out += "." + make_name(arguments[i++]);
12756 "call": function(func, args) {
12757 var f = make(func);
12758 if (f.charAt(0) != "(" && needs_parens(func))
12760 return f + "(" + add_commas(MAP(args, function(expr){
12761 return parenthesize(expr, "seq");
12764 "function": make_function,
12765 "defun": make_function,
12766 "if": function(co, th, el) {
12767 var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ];
12769 out.push("else", make(el));
12771 return add_spaces(out);
12773 "for": function(init, cond, step, block) {
12774 var out = [ "for" ];
12775 init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space);
12776 cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space);
12777 step = (step != null ? make(step) : "").replace(/;*\s*$/, "");
12778 var args = init + cond + step;
12779 if (args == "; ; ") args = ";;";
12780 out.push("(" + args + ")", make(block));
12781 return add_spaces(out);
12783 "for-in": function(vvar, key, hash, block) {
12784 return add_spaces([ "for", "(" +
12785 (vvar ? make(vvar).replace(/;+$/, "") : make(key)),
12787 make(hash) + ")", make(block) ]);
12789 "while": function(condition, block) {
12790 return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]);
12792 "do": function(condition, block) {
12793 return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";";
12795 "return": function(expr) {
12796 var out = [ "return" ];
12797 if (expr != null) out.push(make(expr));
12798 return add_spaces(out) + ";";
12800 "binary": function(operator, lvalue, rvalue) {
12801 var left = make(lvalue), right = make(rvalue);
12802 // XXX: I'm pretty sure other cases will bite here.
12803 // we need to be smarter.
12804 // adding parens all the time is the safest bet.
12805 if (member(lvalue[0], [ "assign", "conditional", "seq" ]) ||
12806 lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]] ||
12807 lvalue[0] == "function" && needs_parens(this)) {
12808 left = "(" + left + ")";
12810 if (member(rvalue[0], [ "assign", "conditional", "seq" ]) ||
12811 rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] &&
12812 !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) {
12813 right = "(" + right + ")";
12815 else if (!beautify && options.inline_script && (operator == "<" || operator == "<<")
12816 && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) {
12817 right = " " + right;
12819 return add_spaces([ left, operator, right ]);
12821 "unary-prefix": function(operator, expr) {
12822 var val = make(expr);
12823 if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
12824 val = "(" + val + ")";
12825 return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val;
12827 "unary-postfix": function(operator, expr) {
12828 var val = make(expr);
12829 if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
12830 val = "(" + val + ")";
12831 return val + operator;
12833 "sub": function(expr, subscript) {
12834 var hash = make(expr);
12835 if (needs_parens(expr))
12836 hash = "(" + hash + ")";
12837 return hash + "[" + make(subscript) + "]";
12839 "object": function(props) {
12840 var obj_needs_parens = needs_parens(this);
12841 if (props.length == 0)
12842 return obj_needs_parens ? "({})" : "{}";
12843 var out = "{" + newline + with_indent(function(){
12844 return MAP(props, function(p){
12845 if (p.length == 3) {
12846 // getter/setter. The name is in p[0], the arg.list in p[1][2], the
12847 // body in p[1][3] and type ("get" / "set") in p[2].
12848 return indent(make_function(p[0], p[1][2], p[1][3], p[2], true));
12850 var key = p[0], val = parenthesize(p[1], "seq");
12851 if (options.quote_keys) {
12852 key = encode_string(key);
12853 } else if ((typeof key == "number" || !beautify && +key + "" == key)
12854 && parseFloat(key) >= 0) {
12855 key = make_num(+key);
12856 } else if (!is_identifier(key)) {
12857 key = encode_string(key);
12859 return indent(add_spaces(beautify && options.space_colon
12860 ? [ key, ":", val ]
12861 : [ key + ":", val ]));
12862 }).join("," + newline);
12863 }) + newline + indent("}");
12864 return obj_needs_parens ? "(" + out + ")" : out;
12866 "regexp": function(rx, mods) {
12867 if (options.ascii_only) rx = to_ascii(rx);
12868 return "/" + rx + "/" + mods;
12870 "array": function(elements) {
12871 if (elements.length == 0) return "[]";
12872 return add_spaces([ "[", add_commas(MAP(elements, function(el, i){
12873 if (!beautify && el[0] == "atom" && el[1] == "undefined") return i === elements.length - 1 ? "," : "";
12874 return parenthesize(el, "seq");
12877 "stat": function(stmt) {
12878 return stmt != null
12879 ? make(stmt).replace(/;*\s*$/, ";")
12882 "seq": function() {
12883 return add_commas(MAP(slice(arguments), make));
12885 "label": function(name, block) {
12886 return add_spaces([ make_name(name), ":", make(block) ]);
12888 "with": function(expr, block) {
12889 return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]);
12891 "atom": function(name) {
12892 return make_name(name);
12894 "directive": function(dir) {
12895 return make_string(dir) + ";";
12897 }, function(){ return make(ast) });
12899 // The squeezer replaces "block"-s that contain only a single
12900 // statement with the statement itself; technically, the AST
12901 // is correct, but this can create problems when we output an
12902 // IF having an ELSE clause where the THEN clause ends in an
12903 // IF *without* an ELSE block (then the outer ELSE would refer
12904 // to the inner IF). This function checks for this case and
12905 // adds the block brackets if needed.
12906 function make_then(th) {
12907 if (th == null) return ";";
12908 if (th[0] == "do") {
12909 // https://github.com/mishoo/UglifyJS/issues/#issue/57
12910 // IE croaks with "syntax error" on code like this:
12911 // if (foo) do ... while(cond); else ...
12912 // we need block brackets around do/while
12913 return make_block([ th ]);
12918 if (type == "if") {
12920 // no else, we must add the block
12921 return make([ "block", [ th ]]);
12924 else if (type == "while" || type == "do") b = b[2];
12925 else if (type == "for" || type == "for-in") b = b[4];
12931 function make_function(name, args, body, keyword, no_parens) {
12932 var out = keyword || "function";
12934 out += " " + make_name(name);
12936 out += "(" + add_commas(MAP(args, make_name)) + ")";
12937 out = add_spaces([ out, make_block(body) ]);
12938 return (!no_parens && needs_parens(this)) ? "(" + out + ")" : out;
12941 function must_has_semicolon(node) {
12945 return empty(node[2]) || must_has_semicolon(node[2]);
12948 return empty(node[4]) || must_has_semicolon(node[4]);
12950 if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else'
12952 if (empty(node[3])) return true; // `else' present but empty
12953 return must_has_semicolon(node[3]); // dive into the `else' branch
12955 return must_has_semicolon(node[2]); // dive into the `then' branch
12961 function make_block_statements(statements, noindent) {
12962 for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
12963 var stat = statements[i];
12964 var code = make(stat);
12966 if (!beautify && i == last && !must_has_semicolon(stat)) {
12967 code = code.replace(/;+\s*$/, "");
12972 return noindent ? a : MAP(a, indent);
12975 function make_switch_block(body) {
12976 var n = body.length;
12977 if (n == 0) return "{}";
12978 return "{" + newline + MAP(body, function(branch, i){
12979 var has_body = branch[1].length > 0, code = with_indent(function(){
12980 return indent(branch[0]
12981 ? add_spaces([ "case", make(branch[0]) + ":" ])
12983 }, 0.5) + (has_body ? newline + with_indent(function(){
12984 return make_block_statements(branch[1]).join(newline);
12986 if (!beautify && has_body && i < n - 1)
12989 }).join(newline) + newline + indent("}");
12992 function make_block(statements) {
12993 if (!statements) return ";";
12994 if (statements.length == 0) return "{}";
12995 return "{" + newline + with_indent(function(){
12996 return make_block_statements(statements).join(newline);
12997 }) + newline + indent("}");
13000 function make_1vardef(def) {
13001 var name = def[0], val = def[1];
13003 name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]);
13009 function split_lines(code, max_line_length) {
13010 var splits = [ 0 ];
13011 jsp.parse(function(){
13012 var next_token = jsp.tokenizer(code);
13013 var last_split = 0;
13015 function current_length(tok) {
13016 return tok.pos - last_split;
13018 function split_here(tok) {
13019 last_split = tok.pos;
13020 splits.push(last_split);
13023 var tok = next_token.apply(this, arguments);
13026 if (prev_token.type == "keyword") break out;
13028 if (current_length(tok) > max_line_length) {
13029 switch (tok.type) {
13042 custom.context = function() {
13043 return next_token.context.apply(this, arguments);
13047 return splits.map(function(pos, i){
13048 return code.substring(pos, splits[i + 1] || code.length);
13052 /* -----[ Utilities ]----- */
13054 function repeat_string(str, i) {
13055 if (i <= 0) return "";
13056 if (i == 1) return str;
13057 var d = repeat_string(str, i >> 1);
13059 if (i & 1) d += str;
13063 function defaults(args, defs) {
13067 for (var i in defs) if (HOP(defs, i)) {
13068 ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
13073 function is_identifier(name) {
13074 return /^[a-z_$][a-z0-9_$]*$/i.test(name)
13076 && !HOP(jsp.KEYWORDS_ATOM, name)
13077 && !HOP(jsp.RESERVED_WORDS, name)
13078 && !HOP(jsp.KEYWORDS, name);
13081 function HOP(obj, prop) {
13082 return Object.prototype.hasOwnProperty.call(obj, prop);
13090 MAP = function(a, f, o) {
13091 var ret = [], top = [], i;
13093 var val = f.call(o, a[i], i);
13094 if (val instanceof AtTop) {
13096 if (val instanceof Splice) {
13097 top.push.apply(top, val.v);
13102 else if (val != skip) {
13103 if (val instanceof Splice) {
13104 ret.push.apply(ret, val.v);
13110 if (a instanceof Array) for (i = 0; i < a.length; ++i) doit();
13111 else for (i in a) if (HOP(a, i)) doit();
13112 return top.concat(ret);
13114 MAP.at_top = function(val) { return new AtTop(val) };
13115 MAP.splice = function(val) { return new Splice(val) };
13116 var skip = MAP.skip = {};
13117 function AtTop(val) { this.v = val };
13118 function Splice(val) { this.v = val };
13121 /* -----[ Exports ]----- */
13123 exports.ast_walker = ast_walker;
13124 exports.ast_mangle = ast_mangle;
13125 exports.ast_squeeze = ast_squeeze;
13126 exports.ast_lift_variables = ast_lift_variables;
13127 exports.gen_code = gen_code;
13128 exports.ast_add_scope = ast_add_scope;
13129 exports.set_logger = function(logger) { warn = logger };
13130 exports.make_string = make_string;
13131 exports.split_lines = split_lines;
13135 exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
13137 // Local variables:
13138 // js-indent-level: 4
13141 define('uglifyjs/index', ["require", "exports", "module", "./parse-js", "./process", "./consolidator"], function(require, exports, module) {
13142 //convienence function(src, [options]);
13143 function uglify(orig_code, options){
13144 options || (options = {});
13145 var jsp = uglify.parser;
13146 var pro = uglify.uglify;
13148 var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST
13149 ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names
13150 ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations
13151 var final_code = pro.gen_code(ast, options.gen_options); // compressed code here
13155 uglify.parser = require("./parse-js");
13156 uglify.uglify = require("./process");
13157 uglify.consolidator = require("./consolidator");
13159 module.exports = uglify
13160 });/* -*- Mode: js; js-indent-level: 2; -*- */
13162 * Copyright 2011 Mozilla Foundation and contributors
13163 * Licensed under the New BSD license. See LICENSE or:
13164 * http://opensource.org/licenses/BSD-3-Clause
13167 define('source-map/array-set', function (require, exports, module) {
13169 var util = require('./util');
13172 * A data structure which is a combination of an array and a set. Adding a new
13173 * member is O(1), testing for membership is O(1), and finding the index of an
13174 * element is O(1). Removing elements from the set is not supported. Only
13175 * strings are supported for membership.
13177 function ArraySet() {
13183 * Static method for creating ArraySet instances from an existing array.
13185 ArraySet.fromArray = function ArraySet_fromArray(aArray) {
13186 var set = new ArraySet();
13187 for (var i = 0, len = aArray.length; i < len; i++) {
13188 set.add(aArray[i]);
13194 * Add the given string to this set.
13196 * @param String aStr
13198 ArraySet.prototype.add = function ArraySet_add(aStr) {
13199 if (this.has(aStr)) {
13200 // Already a member; nothing to do.
13203 var idx = this._array.length;
13204 this._array.push(aStr);
13205 this._set[util.toSetString(aStr)] = idx;
13209 * Is the given string a member of this set?
13211 * @param String aStr
13213 ArraySet.prototype.has = function ArraySet_has(aStr) {
13214 return Object.prototype.hasOwnProperty.call(this._set,
13215 util.toSetString(aStr));
13219 * What is the index of the given string in the array?
13221 * @param String aStr
13223 ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
13224 if (this.has(aStr)) {
13225 return this._set[util.toSetString(aStr)];
13227 throw new Error('"' + aStr + '" is not in the set.');
13231 * What is the element at the given index?
13233 * @param Number aIdx
13235 ArraySet.prototype.at = function ArraySet_at(aIdx) {
13236 if (aIdx >= 0 && aIdx < this._array.length) {
13237 return this._array[aIdx];
13239 throw new Error('No element indexed by ' + aIdx);
13243 * Returns the array representation of this set (which has the proper indices
13244 * indicated by indexOf). Note that this is a copy of the internal array used
13245 * for storing the members so that no one can mess with internal state.
13247 ArraySet.prototype.toArray = function ArraySet_toArray() {
13248 return this._array.slice();
13251 exports.ArraySet = ArraySet;
13254 /* -*- Mode: js; js-indent-level: 2; -*- */
13256 * Copyright 2011 Mozilla Foundation and contributors
13257 * Licensed under the New BSD license. See LICENSE or:
13258 * http://opensource.org/licenses/BSD-3-Clause
13260 * Based on the Base 64 VLQ implementation in Closure Compiler:
13261 * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java
13263 * Copyright 2011 The Closure Compiler Authors. All rights reserved.
13264 * Redistribution and use in source and binary forms, with or without
13265 * modification, are permitted provided that the following conditions are
13268 * * Redistributions of source code must retain the above copyright
13269 * notice, this list of conditions and the following disclaimer.
13270 * * Redistributions in binary form must reproduce the above
13271 * copyright notice, this list of conditions and the following
13272 * disclaimer in the documentation and/or other materials provided
13273 * with the distribution.
13274 * * Neither the name of Google Inc. nor the names of its
13275 * contributors may be used to endorse or promote products derived
13276 * from this software without specific prior written permission.
13278 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
13279 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13280 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
13281 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
13282 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13283 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
13284 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13285 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13286 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13287 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13288 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13291 define('source-map/base64-vlq', function (require, exports, module) {
13293 var base64 = require('./base64');
13295 // A single base 64 digit can contain 6 bits of data. For the base 64 variable
13296 // length quantities we use in the source map spec, the first bit is the sign,
13297 // the next four bits are the actual value, and the 6th bit is the
13298 // continuation bit. The continuation bit tells us whether there are more
13299 // digits in this value following this digit.
13307 var VLQ_BASE_SHIFT = 5;
13310 var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
13313 var VLQ_BASE_MASK = VLQ_BASE - 1;
13316 var VLQ_CONTINUATION_BIT = VLQ_BASE;
13319 * Converts from a two-complement value to a value where the sign bit is
13320 * is placed in the least significant bit. For example, as decimals:
13321 * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
13322 * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
13324 function toVLQSigned(aValue) {
13326 ? ((-aValue) << 1) + 1
13327 : (aValue << 1) + 0;
13331 * Converts to a two-complement value from a value where the sign bit is
13332 * is placed in the least significant bit. For example, as decimals:
13333 * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
13334 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
13336 function fromVLQSigned(aValue) {
13337 var isNegative = (aValue & 1) === 1;
13338 var shifted = aValue >> 1;
13345 * Returns the base 64 VLQ encoded value.
13347 exports.encode = function base64VLQ_encode(aValue) {
13351 var vlq = toVLQSigned(aValue);
13354 digit = vlq & VLQ_BASE_MASK;
13355 vlq >>>= VLQ_BASE_SHIFT;
13357 // There are still more digits in this value, so we must make sure the
13358 // continuation bit is marked.
13359 digit |= VLQ_CONTINUATION_BIT;
13361 encoded += base64.encode(digit);
13368 * Decodes the next base 64 VLQ value from the given string and returns the
13369 * value and the rest of the string.
13371 exports.decode = function base64VLQ_decode(aStr) {
13373 var strLen = aStr.length;
13376 var continuation, digit;
13380 throw new Error("Expected more digits in base 64 VLQ value.");
13382 digit = base64.decode(aStr.charAt(i++));
13383 continuation = !!(digit & VLQ_CONTINUATION_BIT);
13384 digit &= VLQ_BASE_MASK;
13385 result = result + (digit << shift);
13386 shift += VLQ_BASE_SHIFT;
13387 } while (continuation);
13390 value: fromVLQSigned(result),
13391 rest: aStr.slice(i)
13396 /* -*- Mode: js; js-indent-level: 2; -*- */
13398 * Copyright 2011 Mozilla Foundation and contributors
13399 * Licensed under the New BSD license. See LICENSE or:
13400 * http://opensource.org/licenses/BSD-3-Clause
13403 define('source-map/base64', function (require, exports, module) {
13405 var charToIntMap = {};
13406 var intToCharMap = {};
13408 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
13410 .forEach(function (ch, index) {
13411 charToIntMap[ch] = index;
13412 intToCharMap[index] = ch;
13416 * Encode an integer in the range of 0 to 63 to a single base 64 digit.
13418 exports.encode = function base64_encode(aNumber) {
13419 if (aNumber in intToCharMap) {
13420 return intToCharMap[aNumber];
13422 throw new TypeError("Must be between 0 and 63: " + aNumber);
13426 * Decode a single base 64 digit to an integer.
13428 exports.decode = function base64_decode(aChar) {
13429 if (aChar in charToIntMap) {
13430 return charToIntMap[aChar];
13432 throw new TypeError("Not a valid base 64 digit: " + aChar);
13436 /* -*- Mode: js; js-indent-level: 2; -*- */
13438 * Copyright 2011 Mozilla Foundation and contributors
13439 * Licensed under the New BSD license. See LICENSE or:
13440 * http://opensource.org/licenses/BSD-3-Clause
13443 define('source-map/binary-search', function (require, exports, module) {
13446 * Recursive implementation of binary search.
13448 * @param aLow Indices here and lower do not contain the needle.
13449 * @param aHigh Indices here and higher do not contain the needle.
13450 * @param aNeedle The element being searched for.
13451 * @param aHaystack The non-empty array being searched.
13452 * @param aCompare Function which takes two elements and returns -1, 0, or 1.
13454 function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) {
13455 // This function terminates when one of the following is true:
13457 // 1. We find the exact element we are looking for.
13459 // 2. We did not find the exact element, but we can return the next
13460 // closest element that is less than that element.
13462 // 3. We did not find the exact element, and there is no next-closest
13463 // element which is less than the one we are searching for, so we
13465 var mid = Math.floor((aHigh - aLow) / 2) + aLow;
13466 var cmp = aCompare(aNeedle, aHaystack[mid]);
13468 // Found the element we are looking for.
13469 return aHaystack[mid];
13471 else if (cmp > 0) {
13472 // aHaystack[mid] is greater than our needle.
13473 if (aHigh - mid > 1) {
13474 // The element is in the upper half.
13475 return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare);
13477 // We did not find an exact match, return the next closest one
13478 // (termination case 2).
13479 return aHaystack[mid];
13482 // aHaystack[mid] is less than our needle.
13483 if (mid - aLow > 1) {
13484 // The element is in the lower half.
13485 return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare);
13487 // The exact needle element was not found in this haystack. Determine if
13488 // we are in termination case (2) or (3) and return the appropriate thing.
13496 * This is an implementation of binary search which will always try and return
13497 * the next lowest value checked if there is no exact hit. This is because
13498 * mappings between original and generated line/col pairs are single points,
13499 * and there is an implicit region between each of them, so a miss just means
13500 * that you aren't on the very start of a region.
13502 * @param aNeedle The element you are looking for.
13503 * @param aHaystack The array that is being searched.
13504 * @param aCompare A function which takes the needle and an element in the
13505 * array and returns -1, 0, or 1 depending on whether the needle is less
13506 * than, equal to, or greater than the element, respectively.
13508 exports.search = function search(aNeedle, aHaystack, aCompare) {
13509 return aHaystack.length > 0
13510 ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare)
13515 /* -*- Mode: js; js-indent-level: 2; -*- */
13517 * Copyright 2011 Mozilla Foundation and contributors
13518 * Licensed under the New BSD license. See LICENSE or:
13519 * http://opensource.org/licenses/BSD-3-Clause
13522 define('source-map/source-map-consumer', function (require, exports, module) {
13524 var util = require('./util');
13525 var binarySearch = require('./binary-search');
13526 var ArraySet = require('./array-set').ArraySet;
13527 var base64VLQ = require('./base64-vlq');
13530 * A SourceMapConsumer instance represents a parsed source map which we can
13531 * query for information about the original file positions by giving it a file
13532 * position in the generated source.
13534 * The only parameter is the raw source map (either as a JSON string, or
13535 * already parsed to an object). According to the spec, source maps have the
13536 * following attributes:
13538 * - version: Which version of the source map spec this map is following.
13539 * - sources: An array of URLs to the original source files.
13540 * - names: An array of identifiers which can be referrenced by individual mappings.
13541 * - sourceRoot: Optional. The URL root from which all sources are relative.
13542 * - sourcesContent: Optional. An array of contents of the original source files.
13543 * - mappings: A string of base64 VLQs which contain the actual mappings.
13544 * - file: The generated file this source map is associated with.
13546 * Here is an example source map, taken from the source map spec[0]:
13552 * sources: ["foo.js", "bar.js"],
13553 * names: ["src", "maps", "are", "fun"],
13554 * mappings: "AA,AB;;ABCDE;"
13557 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
13559 function SourceMapConsumer(aSourceMap) {
13560 var sourceMap = aSourceMap;
13561 if (typeof aSourceMap === 'string') {
13562 sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
13565 var version = util.getArg(sourceMap, 'version');
13566 var sources = util.getArg(sourceMap, 'sources');
13567 var names = util.getArg(sourceMap, 'names');
13568 var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
13569 var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
13570 var mappings = util.getArg(sourceMap, 'mappings');
13571 var file = util.getArg(sourceMap, 'file');
13573 if (version !== this._version) {
13574 throw new Error('Unsupported version: ' + version);
13577 this._names = ArraySet.fromArray(names);
13578 this._sources = ArraySet.fromArray(sources);
13579 this.sourceRoot = sourceRoot;
13580 this.sourcesContent = sourcesContent;
13583 // `this._generatedMappings` and `this._originalMappings` hold the parsed
13584 // mapping coordinates from the source map's "mappings" attribute. Each
13585 // object in the array is of the form
13588 // generatedLine: The line number in the generated code,
13589 // generatedColumn: The column number in the generated code,
13590 // source: The path to the original source file that generated this
13592 // originalLine: The line number in the original source that
13593 // corresponds to this chunk of generated code,
13594 // originalColumn: The column number in the original source that
13595 // corresponds to this chunk of generated code,
13596 // name: The name of the original symbol which generated this chunk of
13600 // All properties except for `generatedLine` and `generatedColumn` can be
13603 // `this._generatedMappings` is ordered by the generated positions.
13605 // `this._originalMappings` is ordered by the original positions.
13606 this._generatedMappings = [];
13607 this._originalMappings = [];
13608 this._parseMappings(mappings, sourceRoot);
13612 * The version of the source mapping spec that we are consuming.
13614 SourceMapConsumer.prototype._version = 3;
13617 * The list of original sources.
13619 Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
13621 return this._sources.toArray().map(function (s) {
13622 return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
13628 * Parse the mappings in a string in to a data structure which we can easily
13629 * query (an ordered list in this._generatedMappings).
13631 SourceMapConsumer.prototype._parseMappings =
13632 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
13633 var generatedLine = 1;
13634 var previousGeneratedColumn = 0;
13635 var previousOriginalLine = 0;
13636 var previousOriginalColumn = 0;
13637 var previousSource = 0;
13638 var previousName = 0;
13639 var mappingSeparator = /^[,;]/;
13644 while (str.length > 0) {
13645 if (str.charAt(0) === ';') {
13647 str = str.slice(1);
13648 previousGeneratedColumn = 0;
13650 else if (str.charAt(0) === ',') {
13651 str = str.slice(1);
13655 mapping.generatedLine = generatedLine;
13657 // Generated column.
13658 temp = base64VLQ.decode(str);
13659 mapping.generatedColumn = previousGeneratedColumn + temp.value;
13660 previousGeneratedColumn = mapping.generatedColumn;
13663 if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
13664 // Original source.
13665 temp = base64VLQ.decode(str);
13666 mapping.source = this._sources.at(previousSource + temp.value);
13667 previousSource += temp.value;
13669 if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
13670 throw new Error('Found a source, but no line and column');
13674 temp = base64VLQ.decode(str);
13675 mapping.originalLine = previousOriginalLine + temp.value;
13676 previousOriginalLine = mapping.originalLine;
13677 // Lines are stored 0-based
13678 mapping.originalLine += 1;
13680 if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
13681 throw new Error('Found a source and line, but no column');
13684 // Original column.
13685 temp = base64VLQ.decode(str);
13686 mapping.originalColumn = previousOriginalColumn + temp.value;
13687 previousOriginalColumn = mapping.originalColumn;
13690 if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
13692 temp = base64VLQ.decode(str);
13693 mapping.name = this._names.at(previousName + temp.value);
13694 previousName += temp.value;
13699 this._generatedMappings.push(mapping);
13700 if (typeof mapping.originalLine === 'number') {
13701 this._originalMappings.push(mapping);
13706 this._originalMappings.sort(this._compareOriginalPositions);
13710 * Comparator between two mappings where the original positions are compared.
13712 SourceMapConsumer.prototype._compareOriginalPositions =
13713 function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) {
13714 if (mappingA.source > mappingB.source) {
13717 else if (mappingA.source < mappingB.source) {
13721 var cmp = mappingA.originalLine - mappingB.originalLine;
13723 ? mappingA.originalColumn - mappingB.originalColumn
13729 * Comparator between two mappings where the generated positions are compared.
13731 SourceMapConsumer.prototype._compareGeneratedPositions =
13732 function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) {
13733 var cmp = mappingA.generatedLine - mappingB.generatedLine;
13735 ? mappingA.generatedColumn - mappingB.generatedColumn
13740 * Find the mapping that best matches the hypothetical "needle" mapping that
13741 * we are searching for in the given "haystack" of mappings.
13743 SourceMapConsumer.prototype._findMapping =
13744 function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
13745 aColumnName, aComparator) {
13746 // To return the position we are searching for, we must first find the
13747 // mapping for the given position and then return the opposite position it
13748 // points to. Because the mappings are sorted, we can use binary search to
13749 // find the best mapping.
13751 if (aNeedle[aLineName] <= 0) {
13752 throw new TypeError('Line must be greater than or equal to 1, got '
13753 + aNeedle[aLineName]);
13755 if (aNeedle[aColumnName] < 0) {
13756 throw new TypeError('Column must be greater than or equal to 0, got '
13757 + aNeedle[aColumnName]);
13760 return binarySearch.search(aNeedle, aMappings, aComparator);
13764 * Returns the original source, line, and column information for the generated
13765 * source's line and column positions provided. The only argument is an object
13766 * with the following properties:
13768 * - line: The line number in the generated source.
13769 * - column: The column number in the generated source.
13771 * and an object is returned with the following properties:
13773 * - source: The original source file, or null.
13774 * - line: The line number in the original source, or null.
13775 * - column: The column number in the original source, or null.
13776 * - name: The original identifier, or null.
13778 SourceMapConsumer.prototype.originalPositionFor =
13779 function SourceMapConsumer_originalPositionFor(aArgs) {
13781 generatedLine: util.getArg(aArgs, 'line'),
13782 generatedColumn: util.getArg(aArgs, 'column')
13785 var mapping = this._findMapping(needle,
13786 this._generatedMappings,
13789 this._compareGeneratedPositions);
13792 var source = util.getArg(mapping, 'source', null);
13793 if (source && this.sourceRoot) {
13794 source = util.join(this.sourceRoot, source);
13798 line: util.getArg(mapping, 'originalLine', null),
13799 column: util.getArg(mapping, 'originalColumn', null),
13800 name: util.getArg(mapping, 'name', null)
13813 * Returns the original source content. The only argument is the url of the
13814 * original source file. Returns null if no original source content is
13817 SourceMapConsumer.prototype.sourceContentFor =
13818 function SourceMapConsumer_sourceContentFor(aSource) {
13819 if (!this.sourcesContent) {
13823 if (this.sourceRoot) {
13824 aSource = util.relative(this.sourceRoot, aSource);
13827 if (this._sources.has(aSource)) {
13828 return this.sourcesContent[this._sources.indexOf(aSource)];
13832 if (this.sourceRoot
13833 && (url = util.urlParse(this.sourceRoot))) {
13834 // XXX: file:// URIs and absolute paths lead to unexpected behavior for
13835 // many users. We can help them out when they expect file:// URIs to
13836 // behave like it would if they were running a local HTTP server. See
13837 // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
13838 var fileUriAbsPath = aSource.replace(/^file:\/\//, "");
13839 if (url.scheme == "file"
13840 && this._sources.has(fileUriAbsPath)) {
13841 return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
13844 if ((!url.path || url.path == "/")
13845 && this._sources.has("/" + aSource)) {
13846 return this.sourcesContent[this._sources.indexOf("/" + aSource)];
13850 throw new Error('"' + aSource + '" is not in the SourceMap.');
13854 * Returns the generated line and column information for the original source,
13855 * line, and column positions provided. The only argument is an object with
13856 * the following properties:
13858 * - source: The filename of the original source.
13859 * - line: The line number in the original source.
13860 * - column: The column number in the original source.
13862 * and an object is returned with the following properties:
13864 * - line: The line number in the generated source, or null.
13865 * - column: The column number in the generated source, or null.
13867 SourceMapConsumer.prototype.generatedPositionFor =
13868 function SourceMapConsumer_generatedPositionFor(aArgs) {
13870 source: util.getArg(aArgs, 'source'),
13871 originalLine: util.getArg(aArgs, 'line'),
13872 originalColumn: util.getArg(aArgs, 'column')
13875 if (this.sourceRoot) {
13876 needle.source = util.relative(this.sourceRoot, needle.source);
13879 var mapping = this._findMapping(needle,
13880 this._originalMappings,
13883 this._compareOriginalPositions);
13887 line: util.getArg(mapping, 'generatedLine', null),
13888 column: util.getArg(mapping, 'generatedColumn', null)
13898 SourceMapConsumer.GENERATED_ORDER = 1;
13899 SourceMapConsumer.ORIGINAL_ORDER = 2;
13902 * Iterate over each mapping between an original source/line/column and a
13903 * generated line/column in this source map.
13905 * @param Function aCallback
13906 * The function that is called with each mapping.
13907 * @param Object aContext
13908 * Optional. If specified, this object will be the value of `this` every
13909 * time that `aCallback` is called.
13911 * Either `SourceMapConsumer.GENERATED_ORDER` or
13912 * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
13913 * iterate over the mappings sorted by the generated file's line/column
13914 * order or the original's source/line/column order, respectively. Defaults to
13915 * `SourceMapConsumer.GENERATED_ORDER`.
13917 SourceMapConsumer.prototype.eachMapping =
13918 function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
13919 var context = aContext || null;
13920 var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
13924 case SourceMapConsumer.GENERATED_ORDER:
13925 mappings = this._generatedMappings;
13927 case SourceMapConsumer.ORIGINAL_ORDER:
13928 mappings = this._originalMappings;
13931 throw new Error("Unknown order of iteration.");
13934 var sourceRoot = this.sourceRoot;
13935 mappings.map(function (mapping) {
13936 var source = mapping.source;
13937 if (source && sourceRoot) {
13938 source = util.join(sourceRoot, source);
13942 generatedLine: mapping.generatedLine,
13943 generatedColumn: mapping.generatedColumn,
13944 originalLine: mapping.originalLine,
13945 originalColumn: mapping.originalColumn,
13948 }).forEach(aCallback, context);
13951 exports.SourceMapConsumer = SourceMapConsumer;
13954 /* -*- Mode: js; js-indent-level: 2; -*- */
13956 * Copyright 2011 Mozilla Foundation and contributors
13957 * Licensed under the New BSD license. See LICENSE or:
13958 * http://opensource.org/licenses/BSD-3-Clause
13961 define('source-map/source-map-generator', function (require, exports, module) {
13963 var base64VLQ = require('./base64-vlq');
13964 var util = require('./util');
13965 var ArraySet = require('./array-set').ArraySet;
13968 * An instance of the SourceMapGenerator represents a source map which is
13969 * being built incrementally. To create a new one, you must pass an object
13970 * with the following properties:
13972 * - file: The filename of the generated source.
13973 * - sourceRoot: An optional root for all URLs in this source map.
13975 function SourceMapGenerator(aArgs) {
13976 this._file = util.getArg(aArgs, 'file');
13977 this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
13978 this._sources = new ArraySet();
13979 this._names = new ArraySet();
13980 this._mappings = [];
13981 this._sourcesContents = null;
13984 SourceMapGenerator.prototype._version = 3;
13987 * Creates a new SourceMapGenerator based on a SourceMapConsumer
13989 * @param aSourceMapConsumer The SourceMap.
13991 SourceMapGenerator.fromSourceMap =
13992 function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
13993 var sourceRoot = aSourceMapConsumer.sourceRoot;
13994 var generator = new SourceMapGenerator({
13995 file: aSourceMapConsumer.file,
13996 sourceRoot: sourceRoot
13998 aSourceMapConsumer.eachMapping(function (mapping) {
14001 line: mapping.generatedLine,
14002 column: mapping.generatedColumn
14006 if (mapping.source) {
14007 newMapping.source = mapping.source;
14009 newMapping.source = util.relative(sourceRoot, newMapping.source);
14012 newMapping.original = {
14013 line: mapping.originalLine,
14014 column: mapping.originalColumn
14017 if (mapping.name) {
14018 newMapping.name = mapping.name;
14022 generator.addMapping(newMapping);
14024 aSourceMapConsumer.sources.forEach(function (sourceFile) {
14025 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
14027 generator.setSourceContent(sourceFile, content);
14034 * Add a single mapping from original source line and column to the generated
14035 * source's line and column for this source map being created. The mapping
14036 * object should have the following properties:
14038 * - generated: An object with the generated line and column positions.
14039 * - original: An object with the original line and column positions.
14040 * - source: The original source file (relative to the sourceRoot).
14041 * - name: An optional original token name for this mapping.
14043 SourceMapGenerator.prototype.addMapping =
14044 function SourceMapGenerator_addMapping(aArgs) {
14045 var generated = util.getArg(aArgs, 'generated');
14046 var original = util.getArg(aArgs, 'original', null);
14047 var source = util.getArg(aArgs, 'source', null);
14048 var name = util.getArg(aArgs, 'name', null);
14050 this._validateMapping(generated, original, source, name);
14052 if (source && !this._sources.has(source)) {
14053 this._sources.add(source);
14056 if (name && !this._names.has(name)) {
14057 this._names.add(name);
14060 this._mappings.push({
14061 generated: generated,
14062 original: original,
14069 * Set the source content for a source file.
14071 SourceMapGenerator.prototype.setSourceContent =
14072 function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
14073 var source = aSourceFile;
14074 if (this._sourceRoot) {
14075 source = util.relative(this._sourceRoot, source);
14078 if (aSourceContent !== null) {
14079 // Add the source content to the _sourcesContents map.
14080 // Create a new _sourcesContents map if the property is null.
14081 if (!this._sourcesContents) {
14082 this._sourcesContents = {};
14084 this._sourcesContents[util.toSetString(source)] = aSourceContent;
14086 // Remove the source file from the _sourcesContents map.
14087 // If the _sourcesContents map is empty, set the property to null.
14088 delete this._sourcesContents[util.toSetString(source)];
14089 if (Object.keys(this._sourcesContents).length === 0) {
14090 this._sourcesContents = null;
14096 * Applies the mappings of a sub-source-map for a specific source file to the
14097 * source map being generated. Each mapping to the supplied source file is
14098 * rewritten using the supplied source map. Note: The resolution for the
14099 * resulting mappings is the minimium of this map and the supplied map.
14101 * @param aSourceMapConsumer The source map to be applied.
14102 * @param aSourceFile Optional. The filename of the source file.
14103 * If omitted, SourceMapConsumer's file property will be used.
14105 SourceMapGenerator.prototype.applySourceMap =
14106 function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) {
14107 // If aSourceFile is omitted, we will use the file property of the SourceMap
14108 if (!aSourceFile) {
14109 aSourceFile = aSourceMapConsumer.file;
14111 var sourceRoot = this._sourceRoot;
14112 // Make "aSourceFile" relative if an absolute Url is passed.
14114 aSourceFile = util.relative(sourceRoot, aSourceFile);
14116 // Applying the SourceMap can add and remove items from the sources and
14117 // the names array.
14118 var newSources = new ArraySet();
14119 var newNames = new ArraySet();
14121 // Find mappings for the "aSourceFile"
14122 this._mappings.forEach(function (mapping) {
14123 if (mapping.source === aSourceFile && mapping.original) {
14124 // Check if it can be mapped by the source map, then update the mapping.
14125 var original = aSourceMapConsumer.originalPositionFor({
14126 line: mapping.original.line,
14127 column: mapping.original.column
14129 if (original.source !== null) {
14132 mapping.source = util.relative(sourceRoot, original.source);
14134 mapping.source = original.source;
14136 mapping.original.line = original.line;
14137 mapping.original.column = original.column;
14138 if (original.name !== null && mapping.name !== null) {
14139 // Only use the identifier name if it's an identifier
14140 // in both SourceMaps
14141 mapping.name = original.name;
14146 var source = mapping.source;
14147 if (source && !newSources.has(source)) {
14148 newSources.add(source);
14151 var name = mapping.name;
14152 if (name && !newNames.has(name)) {
14153 newNames.add(name);
14157 this._sources = newSources;
14158 this._names = newNames;
14160 // Copy sourcesContents of applied map.
14161 aSourceMapConsumer.sources.forEach(function (sourceFile) {
14162 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
14165 sourceFile = util.relative(sourceRoot, sourceFile);
14167 this.setSourceContent(sourceFile, content);
14173 * A mapping can have one of the three levels of data:
14175 * 1. Just the generated position.
14176 * 2. The Generated position, original position, and original source.
14177 * 3. Generated and original position, original source, as well as a name
14180 * To maintain consistency, we validate that any new mapping being added falls
14181 * in to one of these categories.
14183 SourceMapGenerator.prototype._validateMapping =
14184 function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
14186 if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
14187 && aGenerated.line > 0 && aGenerated.column >= 0
14188 && !aOriginal && !aSource && !aName) {
14192 else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
14193 && aOriginal && 'line' in aOriginal && 'column' in aOriginal
14194 && aGenerated.line > 0 && aGenerated.column >= 0
14195 && aOriginal.line > 0 && aOriginal.column >= 0
14201 throw new Error('Invalid mapping.');
14205 function cmpLocation(loc1, loc2) {
14206 var cmp = (loc1 && loc1.line) - (loc2 && loc2.line);
14207 return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column);
14210 function strcmp(str1, str2) {
14213 return (str1 > str2) - (str1 < str2);
14216 function cmpMapping(mappingA, mappingB) {
14217 return cmpLocation(mappingA.generated, mappingB.generated) ||
14218 cmpLocation(mappingA.original, mappingB.original) ||
14219 strcmp(mappingA.source, mappingB.source) ||
14220 strcmp(mappingA.name, mappingB.name);
14224 * Serialize the accumulated mappings in to the stream of base 64 VLQs
14225 * specified by the source map format.
14227 SourceMapGenerator.prototype._serializeMappings =
14228 function SourceMapGenerator_serializeMappings() {
14229 var previousGeneratedColumn = 0;
14230 var previousGeneratedLine = 1;
14231 var previousOriginalColumn = 0;
14232 var previousOriginalLine = 0;
14233 var previousName = 0;
14234 var previousSource = 0;
14238 // The mappings must be guaranteed to be in sorted order before we start
14239 // serializing them or else the generated line numbers (which are defined
14240 // via the ';' separators) will be all messed up. Note: it might be more
14241 // performant to maintain the sorting as we insert them, rather than as we
14242 // serialize them, but the big O is the same either way.
14243 this._mappings.sort(cmpMapping);
14245 for (var i = 0, len = this._mappings.length; i < len; i++) {
14246 mapping = this._mappings[i];
14248 if (mapping.generated.line !== previousGeneratedLine) {
14249 previousGeneratedColumn = 0;
14250 while (mapping.generated.line !== previousGeneratedLine) {
14252 previousGeneratedLine++;
14257 if (!cmpMapping(mapping, this._mappings[i - 1])) {
14264 result += base64VLQ.encode(mapping.generated.column
14265 - previousGeneratedColumn);
14266 previousGeneratedColumn = mapping.generated.column;
14268 if (mapping.source && mapping.original) {
14269 result += base64VLQ.encode(this._sources.indexOf(mapping.source)
14271 previousSource = this._sources.indexOf(mapping.source);
14273 // lines are stored 0-based in SourceMap spec version 3
14274 result += base64VLQ.encode(mapping.original.line - 1
14275 - previousOriginalLine);
14276 previousOriginalLine = mapping.original.line - 1;
14278 result += base64VLQ.encode(mapping.original.column
14279 - previousOriginalColumn);
14280 previousOriginalColumn = mapping.original.column;
14282 if (mapping.name) {
14283 result += base64VLQ.encode(this._names.indexOf(mapping.name)
14285 previousName = this._names.indexOf(mapping.name);
14294 * Externalize the source map.
14296 SourceMapGenerator.prototype.toJSON =
14297 function SourceMapGenerator_toJSON() {
14299 version: this._version,
14301 sources: this._sources.toArray(),
14302 names: this._names.toArray(),
14303 mappings: this._serializeMappings()
14305 if (this._sourceRoot) {
14306 map.sourceRoot = this._sourceRoot;
14308 if (this._sourcesContents) {
14309 map.sourcesContent = map.sources.map(function (source) {
14310 if (map.sourceRoot) {
14311 source = util.relative(map.sourceRoot, source);
14313 return Object.prototype.hasOwnProperty.call(
14314 this._sourcesContents, util.toSetString(source))
14315 ? this._sourcesContents[util.toSetString(source)]
14323 * Render the source map being generated to a string.
14325 SourceMapGenerator.prototype.toString =
14326 function SourceMapGenerator_toString() {
14327 return JSON.stringify(this);
14330 exports.SourceMapGenerator = SourceMapGenerator;
14333 /* -*- Mode: js; js-indent-level: 2; -*- */
14335 * Copyright 2011 Mozilla Foundation and contributors
14336 * Licensed under the New BSD license. See LICENSE or:
14337 * http://opensource.org/licenses/BSD-3-Clause
14340 define('source-map/source-node', function (require, exports, module) {
14342 var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator;
14343 var util = require('./util');
14346 * SourceNodes provide a way to abstract over interpolating/concatenating
14347 * snippets of generated JavaScript source code while maintaining the line and
14348 * column information associated with the original source code.
14350 * @param aLine The original line number.
14351 * @param aColumn The original column number.
14352 * @param aSource The original source's filename.
14353 * @param aChunks Optional. An array of strings which are snippets of
14354 * generated JS, or other SourceNodes.
14355 * @param aName The original identifier.
14357 function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
14358 this.children = [];
14359 this.sourceContents = {};
14360 this.line = aLine === undefined ? null : aLine;
14361 this.column = aColumn === undefined ? null : aColumn;
14362 this.source = aSource === undefined ? null : aSource;
14363 this.name = aName === undefined ? null : aName;
14364 if (aChunks != null) this.add(aChunks);
14368 * Creates a SourceNode from generated code and a SourceMapConsumer.
14370 * @param aGeneratedCode The generated code
14371 * @param aSourceMapConsumer The SourceMap for the generated code
14373 SourceNode.fromStringWithSourceMap =
14374 function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) {
14375 // The SourceNode we want to fill with the generated code
14376 // and the SourceMap
14377 var node = new SourceNode();
14379 // The generated code
14380 // Processed fragments are removed from this array.
14381 var remainingLines = aGeneratedCode.split('\n');
14383 // We need to remember the position of "remainingLines"
14384 var lastGeneratedLine = 1, lastGeneratedColumn = 0;
14386 // The generate SourceNodes we need a code range.
14387 // To extract it current and last mapping is used.
14388 // Here we store the last mapping.
14389 var lastMapping = null;
14391 aSourceMapConsumer.eachMapping(function (mapping) {
14392 if (lastMapping === null) {
14393 // We add the generated code until the first mapping
14394 // to the SourceNode without any mapping.
14395 // Each line is added as separate string.
14396 while (lastGeneratedLine < mapping.generatedLine) {
14397 node.add(remainingLines.shift() + "\n");
14398 lastGeneratedLine++;
14400 if (lastGeneratedColumn < mapping.generatedColumn) {
14401 var nextLine = remainingLines[0];
14402 node.add(nextLine.substr(0, mapping.generatedColumn));
14403 remainingLines[0] = nextLine.substr(mapping.generatedColumn);
14404 lastGeneratedColumn = mapping.generatedColumn;
14407 // We add the code from "lastMapping" to "mapping":
14408 // First check if there is a new line in between.
14409 if (lastGeneratedLine < mapping.generatedLine) {
14411 // Associate full lines with "lastMapping"
14413 code += remainingLines.shift() + "\n";
14414 lastGeneratedLine++;
14415 lastGeneratedColumn = 0;
14416 } while (lastGeneratedLine < mapping.generatedLine);
14417 // When we reached the correct line, we add code until we
14418 // reach the correct column too.
14419 if (lastGeneratedColumn < mapping.generatedColumn) {
14420 var nextLine = remainingLines[0];
14421 code += nextLine.substr(0, mapping.generatedColumn);
14422 remainingLines[0] = nextLine.substr(mapping.generatedColumn);
14423 lastGeneratedColumn = mapping.generatedColumn;
14425 // Create the SourceNode.
14426 addMappingWithCode(lastMapping, code);
14428 // There is no new line in between.
14429 // Associate the code between "lastGeneratedColumn" and
14430 // "mapping.generatedColumn" with "lastMapping"
14431 var nextLine = remainingLines[0];
14432 var code = nextLine.substr(0, mapping.generatedColumn -
14433 lastGeneratedColumn);
14434 remainingLines[0] = nextLine.substr(mapping.generatedColumn -
14435 lastGeneratedColumn);
14436 lastGeneratedColumn = mapping.generatedColumn;
14437 addMappingWithCode(lastMapping, code);
14440 lastMapping = mapping;
14442 // We have processed all mappings.
14443 // Associate the remaining code in the current line with "lastMapping"
14444 // and add the remaining lines without any mapping
14445 addMappingWithCode(lastMapping, remainingLines.join("\n"));
14447 // Copy sourcesContent into SourceNode
14448 aSourceMapConsumer.sources.forEach(function (sourceFile) {
14449 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
14451 node.setSourceContent(sourceFile, content);
14457 function addMappingWithCode(mapping, code) {
14458 if (mapping.source === undefined) {
14461 node.add(new SourceNode(mapping.originalLine,
14462 mapping.originalColumn,
14471 * Add a chunk of generated JS to this source node.
14473 * @param aChunk A string snippet of generated JS code, another instance of
14474 * SourceNode, or an array where each member is one of those things.
14476 SourceNode.prototype.add = function SourceNode_add(aChunk) {
14477 if (Array.isArray(aChunk)) {
14478 aChunk.forEach(function (chunk) {
14482 else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
14484 this.children.push(aChunk);
14488 throw new TypeError(
14489 "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
14496 * Add a chunk of generated JS to the beginning of this source node.
14498 * @param aChunk A string snippet of generated JS code, another instance of
14499 * SourceNode, or an array where each member is one of those things.
14501 SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
14502 if (Array.isArray(aChunk)) {
14503 for (var i = aChunk.length-1; i >= 0; i--) {
14504 this.prepend(aChunk[i]);
14507 else if (aChunk instanceof SourceNode || typeof aChunk === "string") {
14508 this.children.unshift(aChunk);
14511 throw new TypeError(
14512 "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
14519 * Walk over the tree of JS snippets in this node and its children. The
14520 * walking function is called once for each snippet of JS and is passed that
14521 * snippet and the its original associated source's line/column location.
14523 * @param aFn The traversal function.
14525 SourceNode.prototype.walk = function SourceNode_walk(aFn) {
14526 this.children.forEach(function (chunk) {
14527 if (chunk instanceof SourceNode) {
14531 if (chunk !== '') {
14532 aFn(chunk, { source: this.source,
14534 column: this.column,
14535 name: this.name });
14542 * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between
14543 * each of `this.children`.
14545 * @param aSep The separator.
14547 SourceNode.prototype.join = function SourceNode_join(aSep) {
14550 var len = this.children.length;
14553 for (i = 0; i < len-1; i++) {
14554 newChildren.push(this.children[i]);
14555 newChildren.push(aSep);
14557 newChildren.push(this.children[i]);
14558 this.children = newChildren;
14564 * Call String.prototype.replace on the very right-most source snippet. Useful
14565 * for trimming whitespace from the end of a source node, etc.
14567 * @param aPattern The pattern to replace.
14568 * @param aReplacement The thing to replace the pattern with.
14570 SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
14571 var lastChild = this.children[this.children.length - 1];
14572 if (lastChild instanceof SourceNode) {
14573 lastChild.replaceRight(aPattern, aReplacement);
14575 else if (typeof lastChild === 'string') {
14576 this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
14579 this.children.push(''.replace(aPattern, aReplacement));
14585 * Set the source content for a source file. This will be added to the SourceMapGenerator
14586 * in the sourcesContent field.
14588 * @param aSourceFile The filename of the source file
14589 * @param aSourceContent The content of the source file
14591 SourceNode.prototype.setSourceContent =
14592 function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
14593 this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
14597 * Walk over the tree of SourceNodes. The walking function is called for each
14598 * source file content and is passed the filename and source content.
14600 * @param aFn The traversal function.
14602 SourceNode.prototype.walkSourceContents =
14603 function SourceNode_walkSourceContents(aFn) {
14604 this.children.forEach(function (chunk) {
14605 if (chunk instanceof SourceNode) {
14606 chunk.walkSourceContents(aFn);
14609 Object.keys(this.sourceContents).forEach(function (sourceFileKey) {
14610 aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]);
14615 * Return the string representation of this source node. Walks over the tree
14616 * and concatenates all the various snippets together to one string.
14618 SourceNode.prototype.toString = function SourceNode_toString() {
14620 this.walk(function (chunk) {
14627 * Returns the string representation of this source node along with a source
14630 SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
14636 var map = new SourceMapGenerator(aArgs);
14637 var sourceMappingActive = false;
14638 this.walk(function (chunk, original) {
14639 generated.code += chunk;
14640 if (original.source !== null
14641 && original.line !== null
14642 && original.column !== null) {
14644 source: original.source,
14646 line: original.line,
14647 column: original.column
14650 line: generated.line,
14651 column: generated.column
14653 name: original.name
14655 sourceMappingActive = true;
14656 } else if (sourceMappingActive) {
14659 line: generated.line,
14660 column: generated.column
14663 sourceMappingActive = false;
14665 chunk.split('').forEach(function (ch) {
14668 generated.column = 0;
14670 generated.column++;
14674 this.walkSourceContents(function (sourceFile, sourceContent) {
14675 map.setSourceContent(sourceFile, sourceContent);
14678 return { code: generated.code, map: map };
14681 exports.SourceNode = SourceNode;
14684 /* -*- Mode: js; js-indent-level: 2; -*- */
14686 * Copyright 2011 Mozilla Foundation and contributors
14687 * Licensed under the New BSD license. See LICENSE or:
14688 * http://opensource.org/licenses/BSD-3-Clause
14691 define('source-map/util', function (require, exports, module) {
14694 * This is a helper function for getting values from parameter/options
14697 * @param args The object we are extracting values from
14698 * @param name The name of the property we are getting.
14699 * @param defaultValue An optional value to return if the property is missing
14700 * from the object. If this is not specified and the property is missing, an
14701 * error will be thrown.
14703 function getArg(aArgs, aName, aDefaultValue) {
14704 if (aName in aArgs) {
14705 return aArgs[aName];
14706 } else if (arguments.length === 3) {
14707 return aDefaultValue;
14709 throw new Error('"' + aName + '" is a required argument.');
14712 exports.getArg = getArg;
14714 var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/;
14716 function urlParse(aUrl) {
14717 var match = aUrl.match(urlRegexp);
14729 exports.urlParse = urlParse;
14731 function urlGenerate(aParsedUrl) {
14732 var url = aParsedUrl.scheme + "://";
14733 if (aParsedUrl.auth) {
14734 url += aParsedUrl.auth + "@"
14736 if (aParsedUrl.host) {
14737 url += aParsedUrl.host;
14739 if (aParsedUrl.port) {
14740 url += ":" + aParsedUrl.port
14742 if (aParsedUrl.path) {
14743 url += aParsedUrl.path;
14747 exports.urlGenerate = urlGenerate;
14749 function join(aRoot, aPath) {
14752 if (aPath.match(urlRegexp)) {
14756 if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) {
14758 return urlGenerate(url);
14761 return aRoot.replace(/\/$/, '') + '/' + aPath;
14763 exports.join = join;
14766 * Because behavior goes wacky when you set `__proto__` on objects, we
14767 * have to prefix all the strings in our set with an arbitrary character.
14769 * See https://github.com/mozilla/source-map/pull/31 and
14770 * https://github.com/mozilla/source-map/issues/30
14772 * @param String aStr
14774 function toSetString(aStr) {
14777 exports.toSetString = toSetString;
14779 function fromSetString(aStr) {
14780 return aStr.substr(1);
14782 exports.fromSetString = fromSetString;
14784 function relative(aRoot, aPath) {
14785 aRoot = aRoot.replace(/\/$/, '');
14787 var url = urlParse(aRoot);
14788 if (aPath.charAt(0) == "/" && url && url.path == "/") {
14789 return aPath.slice(1);
14792 return aPath.indexOf(aRoot + '/') === 0
14793 ? aPath.substr(aRoot.length + 1)
14796 exports.relative = relative;
14799 define('source-map', function (require, exports, module) {
14802 * Copyright 2009-2011 Mozilla Foundation and contributors
14803 * Licensed under the New BSD license. See LICENSE.txt or:
14804 * http://opensource.org/licenses/BSD-3-Clause
14806 exports.SourceMapGenerator = require('./source-map/source-map-generator').SourceMapGenerator;
14807 exports.SourceMapConsumer = require('./source-map/source-map-consumer').SourceMapConsumer;
14808 exports.SourceNode = require('./source-map/source-node').SourceNode;
14812 //Distributed under the BSD license:
14813 //Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
14814 define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], function (exports, MOZ_SourceMap, logger, rjsFile) {
14815 (function(exports, global) {
14816 global["UglifyJS"] = exports;
14818 function array_to_hash(a) {
14819 var ret = Object.create(null);
14820 for (var i = 0; i < a.length; ++i) ret[a[i]] = true;
14823 function slice(a, start) {
14824 return Array.prototype.slice.call(a, start || 0);
14826 function characters(str) {
14827 return str.split("");
14829 function member(name, array) {
14830 for (var i = array.length; --i >= 0; ) if (array[i] == name) return true;
14833 function find_if(func, array) {
14834 for (var i = 0, n = array.length; i < n; ++i) {
14835 if (func(array[i])) return array[i];
14838 function repeat_string(str, i) {
14839 if (i <= 0) return "";
14840 if (i == 1) return str;
14841 var d = repeat_string(str, i >> 1);
14843 if (i & 1) d += str;
14846 function DefaultsError(msg, defs) {
14850 function defaults(args, defs, croak) {
14851 if (args === true) args = {};
14852 var ret = args || {};
14853 if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i)) throw new DefaultsError("`" + i + "` is not a supported option", defs);
14854 for (var i in defs) if (defs.hasOwnProperty(i)) {
14855 ret[i] = args && args.hasOwnProperty(i) ? args[i] : defs[i];
14859 function merge(obj, ext) {
14860 for (var i in ext) if (ext.hasOwnProperty(i)) {
14866 var MAP = function() {
14867 function MAP(a, f, backwards) {
14868 var ret = [], top = [], i;
14870 var val = f(a[i], i);
14871 var is_last = val instanceof Last;
14872 if (is_last) val = val.v;
14873 if (val instanceof AtTop) {
14875 if (val instanceof Splice) {
14876 top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
14880 } else if (val !== skip) {
14881 if (val instanceof Splice) {
14882 ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
14889 if (a instanceof Array) {
14891 for (i = a.length; --i >= 0; ) if (doit()) break;
14895 for (i = 0; i < a.length; ++i) if (doit()) break;
14898 for (i in a) if (a.hasOwnProperty(i)) if (doit()) break;
14900 return top.concat(ret);
14902 MAP.at_top = function(val) {
14903 return new AtTop(val);
14905 MAP.splice = function(val) {
14906 return new Splice(val);
14908 MAP.last = function(val) {
14909 return new Last(val);
14911 var skip = MAP.skip = {};
14912 function AtTop(val) {
14915 function Splice(val) {
14918 function Last(val) {
14923 function push_uniq(array, el) {
14924 if (array.indexOf(el) < 0) array.push(el);
14926 function string_template(text, props) {
14927 return text.replace(/\{(.+?)\}/g, function(str, p) {
14931 function remove(array, el) {
14932 for (var i = array.length; --i >= 0; ) {
14933 if (array[i] === el) array.splice(i, 1);
14936 function mergeSort(array, cmp) {
14937 if (array.length < 2) return array.slice();
14938 function merge(a, b) {
14939 var r = [], ai = 0, bi = 0, i = 0;
14940 while (ai < a.length && bi < b.length) {
14941 cmp(a[ai], b[bi]) <= 0 ? r[i++] = a[ai++] : r[i++] = b[bi++];
14943 if (ai < a.length) r.push.apply(r, a.slice(ai));
14944 if (bi < b.length) r.push.apply(r, b.slice(bi));
14948 if (a.length <= 1) return a;
14949 var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
14951 right = _ms(right);
14952 return merge(left, right);
14956 function set_difference(a, b) {
14957 return a.filter(function(el) {
14958 return b.indexOf(el) < 0;
14961 function set_intersection(a, b) {
14962 return a.filter(function(el) {
14963 return b.indexOf(el) >= 0;
14966 function makePredicate(words) {
14967 if (!(words instanceof Array)) words = words.split(" ");
14968 var f = "", cats = [];
14969 out: for (var i = 0; i < words.length; ++i) {
14970 for (var j = 0; j < cats.length; ++j) if (cats[j][0].length == words[i].length) {
14971 cats[j].push(words[i]);
14974 cats.push([ words[i] ]);
14976 function compareTo(arr) {
14977 if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";";
14978 f += "switch(str){";
14979 for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":";
14980 f += "return true}return false;";
14982 if (cats.length > 3) {
14983 cats.sort(function(a, b) {
14984 return b.length - a.length;
14986 f += "switch(str.length){";
14987 for (var i = 0; i < cats.length; ++i) {
14989 f += "case " + cat[0].length + ":";
14996 return new Function("str", f);
14998 function all(array, predicate) {
14999 for (var i = array.length; --i >= 0; ) if (!predicate(array[i])) return false;
15002 function Dictionary() {
15003 this._values = Object.create(null);
15006 Dictionary.prototype = {
15007 set: function(key, val) {
15008 if (!this.has(key)) ++this._size;
15009 this._values["$" + key] = val;
15012 add: function(key, val) {
15013 if (this.has(key)) {
15014 this.get(key).push(val);
15016 this.set(key, [ val ]);
15020 get: function(key) {
15021 return this._values["$" + key];
15023 del: function(key) {
15024 if (this.has(key)) {
15026 delete this._values["$" + key];
15030 has: function(key) {
15031 return "$" + key in this._values;
15033 each: function(f) {
15034 for (var i in this._values) f(this._values[i], i.substr(1));
15041 for (var i in this._values) ret.push(f(this._values[i], i.substr(1)));
15046 function DEFNODE(type, props, methods, base) {
15047 if (arguments.length < 4) base = AST_Node;
15048 if (!props) props = []; else props = props.split(/\s+/);
15049 var self_props = props;
15050 if (base && base.PROPS) props = props.concat(base.PROPS);
15051 var code = "return function AST_" + type + "(props){ if (props) { ";
15052 for (var i = props.length; --i >= 0; ) {
15053 code += "this." + props[i] + " = props." + props[i] + ";";
15055 var proto = base && new base();
15056 if (proto && proto.initialize || methods && methods.initialize) code += "this.initialize();";
15058 var ctor = new Function(code)();
15060 ctor.prototype = proto;
15063 if (base) base.SUBCLASSES.push(ctor);
15064 ctor.prototype.CTOR = ctor;
15065 ctor.PROPS = props || null;
15066 ctor.SELF_PROPS = self_props;
15067 ctor.SUBCLASSES = [];
15069 ctor.prototype.TYPE = ctor.TYPE = type;
15071 if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
15072 if (/^\$/.test(i)) {
15073 ctor[i.substr(1)] = methods[i];
15075 ctor.prototype[i] = methods[i];
15078 ctor.DEFMETHOD = function(name, method) {
15079 this.prototype[name] = method;
15083 var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {}, null);
15084 var AST_Node = DEFNODE("Node", "start end", {
15085 clone: function() {
15086 return new this.CTOR(this);
15088 $documentation: "Base class of all AST nodes",
15090 start: "[AST_Token] The first token of this node",
15091 end: "[AST_Token] The last token of this node"
15093 _walk: function(visitor) {
15094 return visitor._visit(this);
15096 walk: function(visitor) {
15097 return this._walk(visitor);
15100 AST_Node.warn_function = null;
15101 AST_Node.warn = function(txt, props) {
15102 if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props));
15104 var AST_Statement = DEFNODE("Statement", null, {
15105 $documentation: "Base class of all statements"
15107 var AST_Debugger = DEFNODE("Debugger", null, {
15108 $documentation: "Represents a debugger statement"
15110 var AST_Directive = DEFNODE("Directive", "value scope", {
15111 $documentation: 'Represents a directive, like "use strict";',
15113 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
15114 scope: "[AST_Scope/S] The scope that this directive affects"
15117 var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
15118 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
15120 body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
15122 _walk: function(visitor) {
15123 return visitor._visit(this, function() {
15124 this.body._walk(visitor);
15128 function walk_body(node, visitor) {
15129 if (node.body instanceof AST_Statement) {
15130 node.body._walk(visitor);
15131 } else node.body.forEach(function(stat) {
15132 stat._walk(visitor);
15135 var AST_Block = DEFNODE("Block", "body", {
15136 $documentation: "A body of statements (usually bracketed)",
15138 body: "[AST_Statement*] an array of statements"
15140 _walk: function(visitor) {
15141 return visitor._visit(this, function() {
15142 walk_body(this, visitor);
15146 var AST_BlockStatement = DEFNODE("BlockStatement", null, {
15147 $documentation: "A block statement"
15149 var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
15150 $documentation: "The empty statement (empty block or simply a semicolon)",
15151 _walk: function(visitor) {
15152 return visitor._visit(this);
15155 var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
15156 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
15158 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
15160 _walk: function(visitor) {
15161 return visitor._visit(this, function() {
15162 this.body._walk(visitor);
15166 var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
15167 $documentation: "Statement with a label",
15169 label: "[AST_Label] a label definition"
15171 _walk: function(visitor) {
15172 return visitor._visit(this, function() {
15173 this.label._walk(visitor);
15174 this.body._walk(visitor);
15177 }, AST_StatementWithBody);
15178 var AST_DWLoop = DEFNODE("DWLoop", "condition", {
15179 $documentation: "Base class for do/while statements",
15181 condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
15183 _walk: function(visitor) {
15184 return visitor._visit(this, function() {
15185 this.condition._walk(visitor);
15186 this.body._walk(visitor);
15189 }, AST_StatementWithBody);
15190 var AST_Do = DEFNODE("Do", null, {
15191 $documentation: "A `do` statement"
15193 var AST_While = DEFNODE("While", null, {
15194 $documentation: "A `while` statement"
15196 var AST_For = DEFNODE("For", "init condition step", {
15197 $documentation: "A `for` statement",
15199 init: "[AST_Node?] the `for` initialization code, or null if empty",
15200 condition: "[AST_Node?] the `for` termination clause, or null if empty",
15201 step: "[AST_Node?] the `for` update clause, or null if empty"
15203 _walk: function(visitor) {
15204 return visitor._visit(this, function() {
15205 if (this.init) this.init._walk(visitor);
15206 if (this.condition) this.condition._walk(visitor);
15207 if (this.step) this.step._walk(visitor);
15208 this.body._walk(visitor);
15211 }, AST_StatementWithBody);
15212 var AST_ForIn = DEFNODE("ForIn", "init name object", {
15213 $documentation: "A `for ... in` statement",
15215 init: "[AST_Node] the `for/in` initialization code",
15216 name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
15217 object: "[AST_Node] the object that we're looping through"
15219 _walk: function(visitor) {
15220 return visitor._visit(this, function() {
15221 this.init._walk(visitor);
15222 this.object._walk(visitor);
15223 this.body._walk(visitor);
15226 }, AST_StatementWithBody);
15227 var AST_With = DEFNODE("With", "expression", {
15228 $documentation: "A `with` statement",
15230 expression: "[AST_Node] the `with` expression"
15232 _walk: function(visitor) {
15233 return visitor._visit(this, function() {
15234 this.expression._walk(visitor);
15235 this.body._walk(visitor);
15238 }, AST_StatementWithBody);
15239 var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
15240 $documentation: "Base class for all statements introducing a lexical scope",
15242 directives: "[string*/S] an array of directives declared in this scope",
15243 variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
15244 functions: "[Object/S] like `variables`, but only lists function declarations",
15245 uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
15246 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
15247 parent_scope: "[AST_Scope?/S] link to the parent scope",
15248 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
15249 cname: "[integer/S] current index for mangling variables (used internally by the mangler)"
15252 var AST_Toplevel = DEFNODE("Toplevel", "globals", {
15253 $documentation: "The toplevel scope",
15255 globals: "[Object/S] a map of name -> SymbolDef for all undeclared names"
15257 wrap_enclose: function(arg_parameter_pairs) {
15260 var parameters = [];
15261 arg_parameter_pairs.forEach(function(pair) {
15262 var split = pair.split(":");
15263 args.push(split[0]);
15264 parameters.push(split[1]);
15266 var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
15267 wrapped_tl = parse(wrapped_tl);
15268 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
15269 if (node instanceof AST_Directive && node.value == "$ORIG") {
15270 return MAP.splice(self.body);
15275 wrap_commonjs: function(name, export_all) {
15277 var to_export = [];
15279 self.figure_out_scope();
15280 self.walk(new TreeWalker(function(node) {
15281 if (node instanceof AST_SymbolDeclaration && node.definition().global) {
15282 if (!find_if(function(n) {
15283 return n.name == node.name;
15284 }, to_export)) to_export.push(node);
15288 var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
15289 wrapped_tl = parse(wrapped_tl);
15290 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
15291 if (node instanceof AST_SimpleStatement) {
15293 if (node instanceof AST_String) switch (node.getValue()) {
15295 return MAP.splice(self.body);
15299 to_export.forEach(function(sym) {
15300 body.push(new AST_SimpleStatement({
15301 body: new AST_Assign({
15302 left: new AST_Sub({
15303 expression: new AST_SymbolRef({
15306 property: new AST_String({
15311 right: new AST_SymbolRef(sym)
15315 return MAP.splice(body);
15322 var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
15323 $documentation: "Base class for functions",
15325 name: "[AST_SymbolDeclaration?] the name of this function",
15326 argnames: "[AST_SymbolFunarg*] array of function arguments",
15327 uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
15329 _walk: function(visitor) {
15330 return visitor._visit(this, function() {
15331 if (this.name) this.name._walk(visitor);
15332 this.argnames.forEach(function(arg) {
15333 arg._walk(visitor);
15335 walk_body(this, visitor);
15339 var AST_Accessor = DEFNODE("Accessor", null, {
15340 $documentation: "A setter/getter function"
15342 var AST_Function = DEFNODE("Function", null, {
15343 $documentation: "A function expression"
15345 var AST_Defun = DEFNODE("Defun", null, {
15346 $documentation: "A function definition"
15348 var AST_Jump = DEFNODE("Jump", null, {
15349 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
15351 var AST_Exit = DEFNODE("Exit", "value", {
15352 $documentation: "Base class for “exits” (`return` and `throw`)",
15354 value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
15356 _walk: function(visitor) {
15357 return visitor._visit(this, this.value && function() {
15358 this.value._walk(visitor);
15362 var AST_Return = DEFNODE("Return", null, {
15363 $documentation: "A `return` statement"
15365 var AST_Throw = DEFNODE("Throw", null, {
15366 $documentation: "A `throw` statement"
15368 var AST_LoopControl = DEFNODE("LoopControl", "label", {
15369 $documentation: "Base class for loop control statements (`break` and `continue`)",
15371 label: "[AST_LabelRef?] the label, or null if none"
15373 _walk: function(visitor) {
15374 return visitor._visit(this, this.label && function() {
15375 this.label._walk(visitor);
15379 var AST_Break = DEFNODE("Break", null, {
15380 $documentation: "A `break` statement"
15381 }, AST_LoopControl);
15382 var AST_Continue = DEFNODE("Continue", null, {
15383 $documentation: "A `continue` statement"
15384 }, AST_LoopControl);
15385 var AST_If = DEFNODE("If", "condition alternative", {
15386 $documentation: "A `if` statement",
15388 condition: "[AST_Node] the `if` condition",
15389 alternative: "[AST_Statement?] the `else` part, or null if not present"
15391 _walk: function(visitor) {
15392 return visitor._visit(this, function() {
15393 this.condition._walk(visitor);
15394 this.body._walk(visitor);
15395 if (this.alternative) this.alternative._walk(visitor);
15398 }, AST_StatementWithBody);
15399 var AST_Switch = DEFNODE("Switch", "expression", {
15400 $documentation: "A `switch` statement",
15402 expression: "[AST_Node] the `switch` “discriminant”"
15404 _walk: function(visitor) {
15405 return visitor._visit(this, function() {
15406 this.expression._walk(visitor);
15407 walk_body(this, visitor);
15411 var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
15412 $documentation: "Base class for `switch` branches"
15414 var AST_Default = DEFNODE("Default", null, {
15415 $documentation: "A `default` switch branch"
15416 }, AST_SwitchBranch);
15417 var AST_Case = DEFNODE("Case", "expression", {
15418 $documentation: "A `case` switch branch",
15420 expression: "[AST_Node] the `case` expression"
15422 _walk: function(visitor) {
15423 return visitor._visit(this, function() {
15424 this.expression._walk(visitor);
15425 walk_body(this, visitor);
15428 }, AST_SwitchBranch);
15429 var AST_Try = DEFNODE("Try", "bcatch bfinally", {
15430 $documentation: "A `try` statement",
15432 bcatch: "[AST_Catch?] the catch block, or null if not present",
15433 bfinally: "[AST_Finally?] the finally block, or null if not present"
15435 _walk: function(visitor) {
15436 return visitor._visit(this, function() {
15437 walk_body(this, visitor);
15438 if (this.bcatch) this.bcatch._walk(visitor);
15439 if (this.bfinally) this.bfinally._walk(visitor);
15443 var AST_Catch = DEFNODE("Catch", "argname", {
15444 $documentation: "A `catch` node; only makes sense as part of a `try` statement",
15446 argname: "[AST_SymbolCatch] symbol for the exception"
15448 _walk: function(visitor) {
15449 return visitor._visit(this, function() {
15450 this.argname._walk(visitor);
15451 walk_body(this, visitor);
15455 var AST_Finally = DEFNODE("Finally", null, {
15456 $documentation: "A `finally` node; only makes sense as part of a `try` statement"
15458 var AST_Definitions = DEFNODE("Definitions", "definitions", {
15459 $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
15461 definitions: "[AST_VarDef*] array of variable definitions"
15463 _walk: function(visitor) {
15464 return visitor._visit(this, function() {
15465 this.definitions.forEach(function(def) {
15466 def._walk(visitor);
15471 var AST_Var = DEFNODE("Var", null, {
15472 $documentation: "A `var` statement"
15473 }, AST_Definitions);
15474 var AST_Const = DEFNODE("Const", null, {
15475 $documentation: "A `const` statement"
15476 }, AST_Definitions);
15477 var AST_VarDef = DEFNODE("VarDef", "name value", {
15478 $documentation: "A variable declaration; only appears in a AST_Definitions node",
15480 name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
15481 value: "[AST_Node?] initializer, or null of there's no initializer"
15483 _walk: function(visitor) {
15484 return visitor._visit(this, function() {
15485 this.name._walk(visitor);
15486 if (this.value) this.value._walk(visitor);
15490 var AST_Call = DEFNODE("Call", "expression args", {
15491 $documentation: "A function call expression",
15493 expression: "[AST_Node] expression to invoke as function",
15494 args: "[AST_Node*] array of arguments"
15496 _walk: function(visitor) {
15497 return visitor._visit(this, function() {
15498 this.expression._walk(visitor);
15499 this.args.forEach(function(arg) {
15500 arg._walk(visitor);
15505 var AST_New = DEFNODE("New", null, {
15506 $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
15508 var AST_Seq = DEFNODE("Seq", "car cdr", {
15509 $documentation: "A sequence expression (two comma-separated expressions)",
15511 car: "[AST_Node] first element in sequence",
15512 cdr: "[AST_Node] second element in sequence"
15514 $cons: function(x, y) {
15515 var seq = new AST_Seq(x);
15520 $from_array: function(array) {
15521 if (array.length == 0) return null;
15522 if (array.length == 1) return array[0].clone();
15524 for (var i = array.length; --i >= 0; ) {
15525 list = AST_Seq.cons(array[i], list);
15529 if (p.cdr && !p.cdr.cdr) {
15537 to_array: function() {
15538 var p = this, a = [];
15541 if (p.cdr && !(p.cdr instanceof AST_Seq)) {
15549 add: function(node) {
15552 if (!(p.cdr instanceof AST_Seq)) {
15553 var cell = AST_Seq.cons(p.cdr, node);
15554 return p.cdr = cell;
15559 _walk: function(visitor) {
15560 return visitor._visit(this, function() {
15561 this.car._walk(visitor);
15562 if (this.cdr) this.cdr._walk(visitor);
15566 var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
15567 $documentation: 'Base class for property access expressions, i.e. `a.foo` or `a["foo"]`',
15569 expression: "[AST_Node] the “container” expression",
15570 property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
15573 var AST_Dot = DEFNODE("Dot", null, {
15574 $documentation: "A dotted property access expression",
15575 _walk: function(visitor) {
15576 return visitor._visit(this, function() {
15577 this.expression._walk(visitor);
15580 }, AST_PropAccess);
15581 var AST_Sub = DEFNODE("Sub", null, {
15582 $documentation: 'Index-style property access, i.e. `a["foo"]`',
15583 _walk: function(visitor) {
15584 return visitor._visit(this, function() {
15585 this.expression._walk(visitor);
15586 this.property._walk(visitor);
15589 }, AST_PropAccess);
15590 var AST_Unary = DEFNODE("Unary", "operator expression", {
15591 $documentation: "Base class for unary expressions",
15593 operator: "[string] the operator",
15594 expression: "[AST_Node] expression that this unary operator applies to"
15596 _walk: function(visitor) {
15597 return visitor._visit(this, function() {
15598 this.expression._walk(visitor);
15602 var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
15603 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
15605 var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
15606 $documentation: "Unary postfix expression, i.e. `i++`"
15608 var AST_Binary = DEFNODE("Binary", "left operator right", {
15609 $documentation: "Binary expression, i.e. `a + b`",
15611 left: "[AST_Node] left-hand side expression",
15612 operator: "[string] the operator",
15613 right: "[AST_Node] right-hand side expression"
15615 _walk: function(visitor) {
15616 return visitor._visit(this, function() {
15617 this.left._walk(visitor);
15618 this.right._walk(visitor);
15622 var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
15623 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
15625 condition: "[AST_Node]",
15626 consequent: "[AST_Node]",
15627 alternative: "[AST_Node]"
15629 _walk: function(visitor) {
15630 return visitor._visit(this, function() {
15631 this.condition._walk(visitor);
15632 this.consequent._walk(visitor);
15633 this.alternative._walk(visitor);
15637 var AST_Assign = DEFNODE("Assign", null, {
15638 $documentation: "An assignment expression — `a = b + 5`"
15640 var AST_Array = DEFNODE("Array", "elements", {
15641 $documentation: "An array literal",
15643 elements: "[AST_Node*] array of elements"
15645 _walk: function(visitor) {
15646 return visitor._visit(this, function() {
15647 this.elements.forEach(function(el) {
15653 var AST_Object = DEFNODE("Object", "properties", {
15654 $documentation: "An object literal",
15656 properties: "[AST_ObjectProperty*] array of properties"
15658 _walk: function(visitor) {
15659 return visitor._visit(this, function() {
15660 this.properties.forEach(function(prop) {
15661 prop._walk(visitor);
15666 var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
15667 $documentation: "Base class for literal object properties",
15669 key: "[string] the property name; it's always a plain string in our AST, no matter if it was a string, number or identifier in original code",
15670 value: "[AST_Node] property value. For setters and getters this is an AST_Function."
15672 _walk: function(visitor) {
15673 return visitor._visit(this, function() {
15674 this.value._walk(visitor);
15678 var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
15679 $documentation: "A key: value object property"
15680 }, AST_ObjectProperty);
15681 var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
15682 $documentation: "An object setter property"
15683 }, AST_ObjectProperty);
15684 var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
15685 $documentation: "An object getter property"
15686 }, AST_ObjectProperty);
15687 var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
15689 name: "[string] name of this symbol",
15690 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
15691 thedef: "[SymbolDef/S] the definition of this symbol"
15693 $documentation: "Base class for all symbols"
15695 var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
15696 $documentation: "The name of a property accessor (setter/getter function)"
15698 var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
15699 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
15701 init: "[AST_Node*/S] array of initializers for this declaration."
15704 var AST_SymbolVar = DEFNODE("SymbolVar", null, {
15705 $documentation: "Symbol defining a variable"
15706 }, AST_SymbolDeclaration);
15707 var AST_SymbolConst = DEFNODE("SymbolConst", null, {
15708 $documentation: "A constant declaration"
15709 }, AST_SymbolDeclaration);
15710 var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
15711 $documentation: "Symbol naming a function argument"
15713 var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
15714 $documentation: "Symbol defining a function"
15715 }, AST_SymbolDeclaration);
15716 var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
15717 $documentation: "Symbol naming a function expression"
15718 }, AST_SymbolDeclaration);
15719 var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
15720 $documentation: "Symbol naming the exception in catch"
15721 }, AST_SymbolDeclaration);
15722 var AST_Label = DEFNODE("Label", "references", {
15723 $documentation: "Symbol naming a label (declaration)",
15725 references: "[AST_LabelRef*] a list of nodes referring to this label"
15728 var AST_SymbolRef = DEFNODE("SymbolRef", null, {
15729 $documentation: "Reference to some symbol (not definition/declaration)"
15731 var AST_LabelRef = DEFNODE("LabelRef", null, {
15732 $documentation: "Reference to a label symbol"
15734 var AST_This = DEFNODE("This", null, {
15735 $documentation: "The `this` symbol"
15737 var AST_Constant = DEFNODE("Constant", null, {
15738 $documentation: "Base class for all constants",
15739 getValue: function() {
15743 var AST_String = DEFNODE("String", "value", {
15744 $documentation: "A string literal",
15746 value: "[string] the contents of this string"
15749 var AST_Number = DEFNODE("Number", "value", {
15750 $documentation: "A number literal",
15752 value: "[number] the numeric value"
15755 var AST_RegExp = DEFNODE("RegExp", "value", {
15756 $documentation: "A regexp literal",
15758 value: "[RegExp] the actual regexp"
15761 var AST_Atom = DEFNODE("Atom", null, {
15762 $documentation: "Base class for atoms"
15764 var AST_Null = DEFNODE("Null", null, {
15765 $documentation: "The `null` atom",
15768 var AST_NaN = DEFNODE("NaN", null, {
15769 $documentation: "The impossible value",
15772 var AST_Undefined = DEFNODE("Undefined", null, {
15773 $documentation: "The `undefined` value",
15774 value: function() {}()
15776 var AST_Hole = DEFNODE("Hole", null, {
15777 $documentation: "A hole in an array",
15778 value: function() {}()
15780 var AST_Infinity = DEFNODE("Infinity", null, {
15781 $documentation: "The `Infinity` value",
15784 var AST_Boolean = DEFNODE("Boolean", null, {
15785 $documentation: "Base class for booleans"
15787 var AST_False = DEFNODE("False", null, {
15788 $documentation: "The `false` atom",
15791 var AST_True = DEFNODE("True", null, {
15792 $documentation: "The `true` atom",
15795 function TreeWalker(callback) {
15796 this.visit = callback;
15799 TreeWalker.prototype = {
15800 _visit: function(node, descend) {
15801 this.stack.push(node);
15802 var ret = this.visit(node, descend ? function() {
15803 descend.call(node);
15805 if (!ret && descend) {
15806 descend.call(node);
15811 parent: function(n) {
15812 return this.stack[this.stack.length - 2 - (n || 0)];
15814 push: function(node) {
15815 this.stack.push(node);
15818 return this.stack.pop();
15821 return this.stack[this.stack.length - 1];
15823 find_parent: function(type) {
15824 var stack = this.stack;
15825 for (var i = stack.length; --i >= 0; ) {
15827 if (x instanceof type) return x;
15830 in_boolean_context: function() {
15831 var stack = this.stack;
15832 var i = stack.length, self = stack[--i];
15834 var p = stack[--i];
15835 if (p instanceof AST_If && p.condition === self || p instanceof AST_Conditional && p.condition === self || p instanceof AST_DWLoop && p.condition === self || p instanceof AST_For && p.condition === self || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) {
15838 if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) return false;
15842 loopcontrol_target: function(label) {
15843 var stack = this.stack;
15845 for (var i = stack.length; --i >= 0; ) {
15847 if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
15852 for (var i = stack.length; --i >= 0; ) {
15854 if (x instanceof AST_Switch || x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) return x;
15860 var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with";
15861 var KEYWORDS_ATOM = "false null true";
15862 var RESERVED_WORDS = "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile" + " " + KEYWORDS_ATOM + " " + KEYWORDS;
15863 var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case";
15864 KEYWORDS = makePredicate(KEYWORDS);
15865 RESERVED_WORDS = makePredicate(RESERVED_WORDS);
15866 KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
15867 KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
15868 var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
15869 var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
15870 var RE_OCT_NUMBER = /^0[0-7]+$/;
15871 var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
15872 var OPERATORS = makePredicate([ "in", "instanceof", "typeof", "new", "void", "delete", "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]);
15873 var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
15874 var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
15875 var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
15876 var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
15878 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]"),
15879 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]"),
15880 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]"),
15881 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
15883 function is_letter(code) {
15884 return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 170 && UNICODE.letter.test(String.fromCharCode(code));
15886 function is_digit(code) {
15887 return code >= 48 && code <= 57;
15889 function is_alphanumeric_char(code) {
15890 return is_digit(code) || is_letter(code);
15892 function is_unicode_combining_mark(ch) {
15893 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
15895 function is_unicode_connector_punctuation(ch) {
15896 return UNICODE.connector_punctuation.test(ch);
15898 function is_identifier(name) {
15899 return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
15901 function is_identifier_start(code) {
15902 return code == 36 || code == 95 || is_letter(code);
15904 function is_identifier_char(ch) {
15905 var code = ch.charCodeAt(0);
15906 return is_identifier_start(code) || is_digit(code) || code == 8204 || code == 8205 || is_unicode_combining_mark(ch) || is_unicode_connector_punctuation(ch);
15908 function is_identifier_string(str) {
15909 var i = str.length;
15910 if (i == 0) return false;
15911 if (is_digit(str.charCodeAt(0))) return false;
15913 if (!is_identifier_char(str.charAt(i))) return false;
15917 function parse_js_number(num) {
15918 if (RE_HEX_NUMBER.test(num)) {
15919 return parseInt(num.substr(2), 16);
15920 } else if (RE_OCT_NUMBER.test(num)) {
15921 return parseInt(num.substr(1), 8);
15922 } else if (RE_DEC_NUMBER.test(num)) {
15923 return parseFloat(num);
15926 function JS_Parse_Error(message, line, col, pos) {
15927 this.message = message;
15931 this.stack = new Error().stack;
15933 JS_Parse_Error.prototype.toString = function() {
15934 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
15936 function js_error(message, filename, line, col, pos) {
15937 throw new JS_Parse_Error(message, line, col, pos);
15939 function is_token(token, type, val) {
15940 return token.type == type && (val == null || token.value == val);
15943 function tokenizer($TEXT, filename) {
15945 text: $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ""),
15946 filename: filename,
15953 newline_before: false,
15954 regex_allowed: false,
15955 comments_before: []
15958 return S.text.charAt(S.pos);
15960 function next(signal_eof, in_string) {
15961 var ch = S.text.charAt(S.pos++);
15962 if (signal_eof && !ch) throw EX_EOF;
15964 S.newline_before = S.newline_before || !in_string;
15972 function find(what, signal_eof) {
15973 var pos = S.text.indexOf(what, S.pos);
15974 if (signal_eof && pos == -1) throw EX_EOF;
15977 function start_token() {
15978 S.tokline = S.line;
15982 function token(type, value, is_comment) {
15983 S.regex_allowed = type == "operator" && !UNARY_POSTFIX[value] || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value);
15991 nlb: S.newline_before,
15995 ret.comments_before = S.comments_before;
15996 S.comments_before = [];
15997 for (var i = 0, len = ret.comments_before.length; i < len; i++) {
15998 ret.nlb = ret.nlb || ret.comments_before[i].nlb;
16001 S.newline_before = false;
16002 return new AST_Token(ret);
16004 function skip_whitespace() {
16005 while (WHITESPACE_CHARS(peek())) next();
16007 function read_while(pred) {
16008 var ret = "", ch, i = 0;
16009 while ((ch = peek()) && pred(ch, i++)) ret += next();
16012 function parse_error(err) {
16013 js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
16015 function read_num(prefix) {
16016 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
16017 var num = read_while(function(ch, i) {
16018 var code = ch.charCodeAt(0);
16022 return has_x ? false : has_x = true;
16026 return has_x ? true : has_e ? false : has_e = after_e = true;
16029 return after_e || i == 0 && !prefix;
16034 case after_e = false, 46:
16035 return !has_dot && !has_x && !has_e ? has_dot = true : false;
16037 return is_alphanumeric_char(code);
16039 if (prefix) num = prefix + num;
16040 var valid = parse_js_number(num);
16041 if (!isNaN(valid)) {
16042 return token("num", valid);
16044 parse_error("Invalid syntax: " + num);
16047 function read_escaped_char(in_string) {
16048 var ch = next(true, in_string);
16049 switch (ch.charCodeAt(0)) {
16072 return String.fromCharCode(hex_bytes(2));
16075 return String.fromCharCode(hex_bytes(4));
16084 function hex_bytes(n) {
16086 for (;n > 0; --n) {
16087 var digit = parseInt(next(true), 16);
16088 if (isNaN(digit)) parse_error("Invalid hex-character pattern in string");
16089 num = num << 4 | digit;
16093 var read_string = with_eof_error("Unterminated string constant", function() {
16094 var quote = next(), ret = "";
16096 var ch = next(true);
16098 var octal_len = 0, first = null;
16099 ch = read_while(function(ch) {
16100 if (ch >= "0" && ch <= "7") {
16103 return ++octal_len;
16104 } else if (first <= "3" && octal_len <= 2) return ++octal_len; else if (first >= "4" && octal_len <= 1) return ++octal_len;
16108 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); else ch = read_escaped_char(true);
16109 } else if (ch == quote) break;
16112 return token("string", ret);
16114 function read_line_comment() {
16116 var i = find("\n"), ret;
16118 ret = S.text.substr(S.pos);
16119 S.pos = S.text.length;
16121 ret = S.text.substring(S.pos, i);
16124 return token("comment1", ret, true);
16126 var read_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
16128 var i = find("*/", true);
16129 var text = S.text.substring(S.pos, i);
16130 var a = text.split("\n"), n = a.length;
16133 if (n > 1) S.col = a[n - 1].length; else S.col += a[n - 1].length;
16135 S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
16136 return token("comment2", text, true);
16138 function read_name() {
16139 var backslash = false, name = "", ch, escaped = false, hex;
16140 while ((ch = peek()) != null) {
16142 if (ch == "\\") escaped = backslash = true, next(); else if (is_identifier_char(ch)) name += next(); else break;
16144 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
16145 ch = read_escaped_char();
16146 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
16151 if (KEYWORDS(name) && escaped) {
16152 hex = name.charCodeAt(0).toString(16).toUpperCase();
16153 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
16157 var read_regexp = with_eof_error("Unterminated regular expression", function(regexp) {
16158 var prev_backslash = false, ch, in_class = false;
16159 while (ch = next(true)) if (prev_backslash) {
16160 regexp += "\\" + ch;
16161 prev_backslash = false;
16162 } else if (ch == "[") {
16165 } else if (ch == "]" && in_class) {
16168 } else if (ch == "/" && !in_class) {
16170 } else if (ch == "\\") {
16171 prev_backslash = true;
16175 var mods = read_name();
16176 return token("regexp", new RegExp(regexp, mods));
16178 function read_operator(prefix) {
16179 function grow(op) {
16180 if (!peek()) return op;
16181 var bigger = op + peek();
16182 if (OPERATORS(bigger)) {
16184 return grow(bigger);
16189 return token("operator", grow(prefix || next()));
16191 function handle_slash() {
16193 var regex_allowed = S.regex_allowed;
16196 S.comments_before.push(read_line_comment());
16197 S.regex_allowed = regex_allowed;
16198 return next_token();
16201 S.comments_before.push(read_multiline_comment());
16202 S.regex_allowed = regex_allowed;
16203 return next_token();
16205 return S.regex_allowed ? read_regexp("") : read_operator("/");
16207 function handle_dot() {
16209 return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", ".");
16211 function read_word() {
16212 var word = read_name();
16213 return KEYWORDS_ATOM(word) ? token("atom", word) : !KEYWORDS(word) ? token("name", word) : OPERATORS(word) ? token("operator", word) : token("keyword", word);
16215 function with_eof_error(eof_error, cont) {
16216 return function(x) {
16220 if (ex === EX_EOF) parse_error(eof_error); else throw ex;
16224 function next_token(force_regexp) {
16225 if (force_regexp != null) return read_regexp(force_regexp);
16229 if (!ch) return token("eof");
16230 var code = ch.charCodeAt(0);
16234 return read_string();
16237 return handle_dot();
16240 return handle_slash();
16242 if (is_digit(code)) return read_num();
16243 if (PUNC_CHARS(ch)) return token("punc", next());
16244 if (OPERATOR_CHARS(ch)) return read_operator();
16245 if (code == 92 || is_identifier_start(code)) return read_word();
16246 parse_error("Unexpected character '" + ch + "'");
16248 next_token.context = function(nc) {
16254 var UNARY_PREFIX = makePredicate([ "typeof", "void", "delete", "--", "++", "!", "~", "-", "+" ]);
16255 var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
16256 var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
16257 var PRECEDENCE = function(a, ret) {
16258 for (var i = 0, n = 1; i < a.length; ++i, ++n) {
16260 for (var j = 0; j < b.length; ++j) {
16265 }([ [ "||" ], [ "&&" ], [ "|" ], [ "^" ], [ "&" ], [ "==", "===", "!=", "!==" ], [ "<", ">", "<=", ">=", "in", "instanceof" ], [ ">>", "<<", ">>>" ], [ "+", "-" ], [ "*", "/", "%" ] ], {});
16266 var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
16267 var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
16268 function parse($TEXT, options) {
16269 options = defaults(options, {
16276 input: typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT,
16281 in_directives: true,
16286 function is(type, value) {
16287 return is_token(S.token, type, value);
16290 return S.peeked || (S.peeked = S.input());
16295 S.token = S.peeked;
16298 S.token = S.input();
16300 S.in_directives = S.in_directives && (S.token.type == "string" || is("punc", ";"));
16306 function croak(msg, line, col, pos) {
16307 var ctx = S.input.context();
16308 js_error(msg, ctx.filename, line != null ? line : ctx.tokline, col != null ? col : ctx.tokcol, pos != null ? pos : ctx.tokpos);
16310 function token_error(token, msg) {
16311 croak(msg, token.line, token.col);
16313 function unexpected(token) {
16314 if (token == null) token = S.token;
16315 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
16317 function expect_token(type, val) {
16318 if (is(type, val)) {
16321 token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
16323 function expect(punc) {
16324 return expect_token("punc", punc);
16326 function can_insert_semicolon() {
16327 return !options.strict && (S.token.nlb || is("eof") || is("punc", "}"));
16329 function semicolon() {
16330 if (is("punc", ";")) next(); else if (!can_insert_semicolon()) unexpected();
16332 function parenthesised() {
16334 var exp = expression(true);
16338 function embed_tokens(parser) {
16339 return function() {
16340 var start = S.token;
16341 var expr = parser();
16343 expr.start = start;
16348 var statement = embed_tokens(function() {
16350 if (is("operator", "/") || is("operator", "/=")) {
16352 S.token = S.input(S.token.value.substr(1));
16354 switch (S.token.type) {
16356 var dir = S.in_directives, stat = simple_statement();
16357 if (dir && stat.body instanceof AST_String && !is("punc", ",")) return new AST_Directive({
16358 value: stat.body.value
16366 return simple_statement();
16369 return is_token(peek(), "punc", ":") ? labeled_statement() : simple_statement();
16372 switch (S.token.value) {
16374 return new AST_BlockStatement({
16382 return simple_statement();
16386 return new AST_EmptyStatement();
16393 switch (tmp = S.token.value, next(), tmp) {
16395 return break_cont(AST_Break);
16398 return break_cont(AST_Continue);
16402 return new AST_Debugger();
16405 return new AST_Do({
16406 body: in_loop(statement),
16407 condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(),
16412 return new AST_While({
16413 condition: parenthesised(),
16414 body: in_loop(statement)
16421 return function_(true);
16427 if (S.in_function == 0) croak("'return' outside of function");
16428 return new AST_Return({
16429 value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true),
16434 return new AST_Switch({
16435 expression: parenthesised(),
16436 body: in_loop(switch_body_)
16440 if (S.token.nlb) croak("Illegal newline after 'throw'");
16441 return new AST_Throw({
16442 value: (tmp = expression(true), semicolon(), tmp)
16449 return tmp = var_(), semicolon(), tmp;
16452 return tmp = const_(), semicolon(), tmp;
16455 return new AST_With({
16456 expression: parenthesised(),
16465 function labeled_statement() {
16466 var label = as_symbol(AST_Label);
16467 if (find_if(function(l) {
16468 return l.name == label.name;
16470 croak("Label " + label.name + " defined twice");
16473 S.labels.push(label);
16474 var stat = statement();
16476 return new AST_LabeledStatement({
16481 function simple_statement(tmp) {
16482 return new AST_SimpleStatement({
16483 body: (tmp = expression(true), semicolon(), tmp)
16486 function break_cont(type) {
16488 if (!can_insert_semicolon()) {
16489 label = as_symbol(AST_LabelRef, true);
16491 if (label != null) {
16492 if (!find_if(function(l) {
16493 return l.name == label.name;
16494 }, S.labels)) croak("Undefined label " + label.name);
16495 } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
16504 if (!is("punc", ";")) {
16505 init = is("keyword", "var") ? (next(), var_(true)) : expression(true, true);
16506 if (is("operator", "in")) {
16507 if (init instanceof AST_Var && init.definitions.length > 1) croak("Only one variable declaration allowed in for..in loop");
16509 return for_in(init);
16512 return regular_for(init);
16514 function regular_for(init) {
16516 var test = is("punc", ";") ? null : expression(true);
16518 var step = is("punc", ")") ? null : expression(true);
16520 return new AST_For({
16524 body: in_loop(statement)
16527 function for_in(init) {
16528 var lhs = init instanceof AST_Var ? init.definitions[0].name : null;
16529 var obj = expression(true);
16531 return new AST_ForIn({
16535 body: in_loop(statement)
16538 var function_ = function(in_statement, ctor) {
16539 var is_accessor = ctor === AST_Accessor;
16540 var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : is_accessor ? AST_SymbolAccessor : AST_SymbolLambda) : is_accessor && (is("string") || is("num")) ? as_atom_node() : null;
16541 if (in_statement && !name) unexpected();
16543 if (!ctor) ctor = in_statement ? AST_Defun : AST_Function;
16546 argnames: function(first, a) {
16547 while (!is("punc", ")")) {
16548 if (first) first = false; else expect(",");
16549 a.push(as_symbol(AST_SymbolFunarg));
16554 body: function(loop, labels) {
16556 S.in_directives = true;
16564 }(S.in_loop, S.labels)
16568 var cond = parenthesised(), body = statement(), belse = null;
16569 if (is("keyword", "else")) {
16571 belse = statement();
16573 return new AST_If({
16579 function block_() {
16582 while (!is("punc", "}")) {
16583 if (is("eof")) unexpected();
16584 a.push(statement());
16589 function switch_body_() {
16591 var a = [], cur = null, branch = null, tmp;
16592 while (!is("punc", "}")) {
16593 if (is("eof")) unexpected();
16594 if (is("keyword", "case")) {
16595 if (branch) branch.end = prev();
16597 branch = new AST_Case({
16598 start: (tmp = S.token, next(), tmp),
16599 expression: expression(true),
16604 } else if (is("keyword", "default")) {
16605 if (branch) branch.end = prev();
16607 branch = new AST_Default({
16608 start: (tmp = S.token, next(), expect(":"), tmp),
16613 if (!cur) unexpected();
16614 cur.push(statement());
16617 if (branch) branch.end = prev();
16622 var body = block_(), bcatch = null, bfinally = null;
16623 if (is("keyword", "catch")) {
16624 var start = S.token;
16627 var name = as_symbol(AST_SymbolCatch);
16629 bcatch = new AST_Catch({
16636 if (is("keyword", "finally")) {
16637 var start = S.token;
16639 bfinally = new AST_Finally({
16645 if (!bcatch && !bfinally) croak("Missing catch/finally blocks");
16646 return new AST_Try({
16652 function vardefs(no_in, in_const) {
16655 a.push(new AST_VarDef({
16657 name: as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
16658 value: is("operator", "=") ? (next(), expression(false, no_in)) : null,
16661 if (!is("punc", ",")) break;
16666 var var_ = function(no_in) {
16667 return new AST_Var({
16669 definitions: vardefs(no_in, false),
16673 var const_ = function() {
16674 return new AST_Const({
16676 definitions: vardefs(false, true),
16680 var new_ = function() {
16681 var start = S.token;
16682 expect_token("operator", "new");
16683 var newexp = expr_atom(false), args;
16684 if (is("punc", "(")) {
16686 args = expr_list(")");
16690 return subscripts(new AST_New({
16692 expression: newexp,
16697 function as_atom_node() {
16698 var tok = S.token, ret;
16699 switch (tok.type) {
16701 return as_symbol(AST_SymbolRef);
16704 ret = new AST_Number({
16712 ret = new AST_String({
16720 ret = new AST_RegExp({
16728 switch (tok.value) {
16730 ret = new AST_False({
16737 ret = new AST_True({
16744 ret = new AST_Null({
16755 var expr_atom = function(allow_calls) {
16756 if (is("operator", "new")) {
16759 var start = S.token;
16761 switch (start.value) {
16764 var ex = expression(true);
16768 return subscripts(ex, allow_calls);
16771 return subscripts(array_(), allow_calls);
16774 return subscripts(object_(), allow_calls);
16778 if (is("keyword", "function")) {
16780 var func = function_(false);
16781 func.start = start;
16783 return subscripts(func, allow_calls);
16785 if (ATOMIC_START_TOKEN[S.token.type]) {
16786 return subscripts(as_atom_node(), allow_calls);
16790 function expr_list(closing, allow_trailing_comma, allow_empty) {
16791 var first = true, a = [];
16792 while (!is("punc", closing)) {
16793 if (first) first = false; else expect(",");
16794 if (allow_trailing_comma && is("punc", closing)) break;
16795 if (is("punc", ",") && allow_empty) {
16796 a.push(new AST_Hole({
16801 a.push(expression(false));
16807 var array_ = embed_tokens(function() {
16809 return new AST_Array({
16810 elements: expr_list("]", !options.strict, true)
16813 var object_ = embed_tokens(function() {
16815 var first = true, a = [];
16816 while (!is("punc", "}")) {
16817 if (first) first = false; else expect(",");
16818 if (!options.strict && is("punc", "}")) break;
16819 var start = S.token;
16820 var type = start.type;
16821 var name = as_property_name();
16822 if (type == "name" && !is("punc", ":")) {
16823 if (name == "get") {
16824 a.push(new AST_ObjectGetter({
16827 value: function_(false, AST_Accessor),
16832 if (name == "set") {
16833 a.push(new AST_ObjectSetter({
16836 value: function_(false, AST_Accessor),
16843 a.push(new AST_ObjectKeyVal({
16846 value: expression(false),
16851 return new AST_Object({
16855 function as_property_name() {
16858 switch (tmp.type) {
16871 function as_name() {
16874 switch (tmp.type) {
16885 function as_symbol(type, noerror) {
16887 if (!noerror) croak("Name expected");
16890 var name = S.token.value;
16891 var sym = new (name == "this" ? AST_This : type)({
16892 name: String(S.token.value),
16899 var subscripts = function(expr, allow_calls) {
16900 var start = expr.start;
16901 if (is("punc", ".")) {
16903 return subscripts(new AST_Dot({
16906 property: as_name(),
16910 if (is("punc", "[")) {
16912 var prop = expression(true);
16914 return subscripts(new AST_Sub({
16921 if (allow_calls && is("punc", "(")) {
16923 return subscripts(new AST_Call({
16926 args: expr_list(")"),
16932 var maybe_unary = function(allow_calls) {
16933 var start = S.token;
16934 if (is("operator") && UNARY_PREFIX(start.value)) {
16936 var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
16941 var val = expr_atom(allow_calls);
16942 while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
16943 val = make_unary(AST_UnaryPostfix, S.token.value, val);
16950 function make_unary(ctor, op, expr) {
16951 if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator");
16957 var expr_op = function(left, min_prec, no_in) {
16958 var op = is("operator") ? S.token.value : null;
16959 if (op == "in" && no_in) op = null;
16960 var prec = op != null ? PRECEDENCE[op] : null;
16961 if (prec != null && prec > min_prec) {
16963 var right = expr_op(maybe_unary(true), prec, no_in);
16964 return expr_op(new AST_Binary({
16970 }), min_prec, no_in);
16974 function expr_ops(no_in) {
16975 return expr_op(maybe_unary(true), 0, no_in);
16977 var maybe_conditional = function(no_in) {
16978 var start = S.token;
16979 var expr = expr_ops(no_in);
16980 if (is("operator", "?")) {
16982 var yes = expression(false);
16984 return new AST_Conditional({
16988 alternative: expression(false, no_in),
16994 function is_assignable(expr) {
16995 if (!options.strict) return true;
16996 if (expr instanceof AST_This) return false;
16997 return expr instanceof AST_PropAccess || expr instanceof AST_Symbol;
16999 var maybe_assign = function(no_in) {
17000 var start = S.token;
17001 var left = maybe_conditional(no_in), val = S.token.value;
17002 if (is("operator") && ASSIGNMENT(val)) {
17003 if (is_assignable(left)) {
17005 return new AST_Assign({
17009 right: maybe_assign(no_in),
17013 croak("Invalid assignment");
17017 var expression = function(commas, no_in) {
17018 var start = S.token;
17019 var expr = maybe_assign(no_in);
17020 if (commas && is("punc", ",")) {
17022 return new AST_Seq({
17025 cdr: expression(true, no_in),
17031 function in_loop(cont) {
17037 if (options.expression) {
17038 return expression(true);
17040 return function() {
17041 var start = S.token;
17043 while (!is("eof")) body.push(statement());
17045 var toplevel = options.toplevel;
17047 toplevel.body = toplevel.body.concat(body);
17048 toplevel.end = end;
17050 toplevel = new AST_Toplevel({
17060 function TreeTransformer(before, after) {
17061 TreeWalker.call(this);
17062 this.before = before;
17063 this.after = after;
17065 TreeTransformer.prototype = new TreeWalker();
17066 (function(undefined) {
17067 function _(node, descend) {
17068 node.DEFMETHOD("transform", function(tw, in_list) {
17071 if (tw.before) x = tw.before(this, descend, in_list);
17072 if (x === undefined) {
17077 tw.stack[tw.stack.length - 1] = x = this.clone();
17079 y = tw.after(x, in_list);
17080 if (y !== undefined) x = y;
17087 function do_list(list, tw) {
17088 return MAP(list, function(node) {
17089 return node.transform(tw, true);
17093 _(AST_LabeledStatement, function(self, tw) {
17094 self.label = self.label.transform(tw);
17095 self.body = self.body.transform(tw);
17097 _(AST_SimpleStatement, function(self, tw) {
17098 self.body = self.body.transform(tw);
17100 _(AST_Block, function(self, tw) {
17101 self.body = do_list(self.body, tw);
17103 _(AST_DWLoop, function(self, tw) {
17104 self.condition = self.condition.transform(tw);
17105 self.body = self.body.transform(tw);
17107 _(AST_For, function(self, tw) {
17108 if (self.init) self.init = self.init.transform(tw);
17109 if (self.condition) self.condition = self.condition.transform(tw);
17110 if (self.step) self.step = self.step.transform(tw);
17111 self.body = self.body.transform(tw);
17113 _(AST_ForIn, function(self, tw) {
17114 self.init = self.init.transform(tw);
17115 self.object = self.object.transform(tw);
17116 self.body = self.body.transform(tw);
17118 _(AST_With, function(self, tw) {
17119 self.expression = self.expression.transform(tw);
17120 self.body = self.body.transform(tw);
17122 _(AST_Exit, function(self, tw) {
17123 if (self.value) self.value = self.value.transform(tw);
17125 _(AST_LoopControl, function(self, tw) {
17126 if (self.label) self.label = self.label.transform(tw);
17128 _(AST_If, function(self, tw) {
17129 self.condition = self.condition.transform(tw);
17130 self.body = self.body.transform(tw);
17131 if (self.alternative) self.alternative = self.alternative.transform(tw);
17133 _(AST_Switch, function(self, tw) {
17134 self.expression = self.expression.transform(tw);
17135 self.body = do_list(self.body, tw);
17137 _(AST_Case, function(self, tw) {
17138 self.expression = self.expression.transform(tw);
17139 self.body = do_list(self.body, tw);
17141 _(AST_Try, function(self, tw) {
17142 self.body = do_list(self.body, tw);
17143 if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
17144 if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
17146 _(AST_Catch, function(self, tw) {
17147 self.argname = self.argname.transform(tw);
17148 self.body = do_list(self.body, tw);
17150 _(AST_Definitions, function(self, tw) {
17151 self.definitions = do_list(self.definitions, tw);
17153 _(AST_VarDef, function(self, tw) {
17154 if (self.value) self.value = self.value.transform(tw);
17156 _(AST_Lambda, function(self, tw) {
17157 if (self.name) self.name = self.name.transform(tw);
17158 self.argnames = do_list(self.argnames, tw);
17159 self.body = do_list(self.body, tw);
17161 _(AST_Call, function(self, tw) {
17162 self.expression = self.expression.transform(tw);
17163 self.args = do_list(self.args, tw);
17165 _(AST_Seq, function(self, tw) {
17166 self.car = self.car.transform(tw);
17167 self.cdr = self.cdr.transform(tw);
17169 _(AST_Dot, function(self, tw) {
17170 self.expression = self.expression.transform(tw);
17172 _(AST_Sub, function(self, tw) {
17173 self.expression = self.expression.transform(tw);
17174 self.property = self.property.transform(tw);
17176 _(AST_Unary, function(self, tw) {
17177 self.expression = self.expression.transform(tw);
17179 _(AST_Binary, function(self, tw) {
17180 self.left = self.left.transform(tw);
17181 self.right = self.right.transform(tw);
17183 _(AST_Conditional, function(self, tw) {
17184 self.condition = self.condition.transform(tw);
17185 self.consequent = self.consequent.transform(tw);
17186 self.alternative = self.alternative.transform(tw);
17188 _(AST_Array, function(self, tw) {
17189 self.elements = do_list(self.elements, tw);
17191 _(AST_Object, function(self, tw) {
17192 self.properties = do_list(self.properties, tw);
17194 _(AST_ObjectProperty, function(self, tw) {
17195 self.value = self.value.transform(tw);
17199 function SymbolDef(scope, index, orig) {
17200 this.name = orig.name;
17201 this.orig = [ orig ];
17202 this.scope = scope;
17203 this.references = [];
17204 this.global = false;
17205 this.mangled_name = null;
17206 this.undeclared = false;
17207 this.constant = false;
17208 this.index = index;
17210 SymbolDef.prototype = {
17211 unmangleable: function(options) {
17212 return this.global && !(options && options.toplevel) || this.undeclared || !(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with);
17214 mangle: function(options) {
17215 if (!this.mangled_name && !this.unmangleable(options)) {
17216 var s = this.scope;
17217 if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8) s = s.parent_scope;
17218 this.mangled_name = s.next_mangled(options);
17222 AST_Toplevel.DEFMETHOD("figure_out_scope", function() {
17224 var scope = self.parent_scope = null;
17225 var labels = new Dictionary();
17227 var tw = new TreeWalker(function(node, descend) {
17228 if (node instanceof AST_Scope) {
17229 node.init_scope_vars(nesting);
17230 var save_scope = node.parent_scope = scope;
17231 var save_labels = labels;
17234 labels = new Dictionary();
17236 labels = save_labels;
17237 scope = save_scope;
17241 if (node instanceof AST_Directive) {
17242 node.scope = scope;
17243 push_uniq(scope.directives, node.value);
17246 if (node instanceof AST_With) {
17247 for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
17250 if (node instanceof AST_LabeledStatement) {
17251 var l = node.label;
17252 if (labels.has(l.name)) throw new Error(string_template("Label {name} defined twice", l));
17253 labels.set(l.name, l);
17255 labels.del(l.name);
17258 if (node instanceof AST_Symbol) {
17259 node.scope = scope;
17261 if (node instanceof AST_Label) {
17262 node.thedef = node;
17263 node.init_scope_vars();
17265 if (node instanceof AST_SymbolLambda) {
17266 scope.def_function(node);
17267 } else if (node instanceof AST_SymbolDefun) {
17268 (node.scope = scope.parent_scope).def_function(node);
17269 } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) {
17270 var def = scope.def_variable(node);
17271 def.constant = node instanceof AST_SymbolConst;
17272 def.init = tw.parent().value;
17273 } else if (node instanceof AST_SymbolCatch) {
17274 scope.def_variable(node);
17276 if (node instanceof AST_LabelRef) {
17277 var sym = labels.get(node.name);
17278 if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
17280 line: node.start.line,
17281 col: node.start.col
17288 var globals = self.globals = new Dictionary();
17289 var tw = new TreeWalker(function(node, descend) {
17290 if (node instanceof AST_Lambda) {
17291 var prev_func = func;
17297 if (node instanceof AST_LabelRef) {
17301 if (node instanceof AST_SymbolRef) {
17302 var name = node.name;
17303 var sym = node.scope.find_variable(name);
17306 if (globals.has(name)) {
17307 g = globals.get(name);
17309 g = new SymbolDef(self, globals.size(), node);
17310 g.undeclared = true;
17312 globals.set(name, g);
17315 if (name == "eval" && tw.parent() instanceof AST_Call) {
17316 for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) s.uses_eval = true;
17318 if (name == "arguments") {
17319 func.uses_arguments = true;
17330 AST_Scope.DEFMETHOD("init_scope_vars", function(nesting) {
17331 this.directives = [];
17332 this.variables = new Dictionary();
17333 this.functions = new Dictionary();
17334 this.uses_with = false;
17335 this.uses_eval = false;
17336 this.parent_scope = null;
17337 this.enclosed = [];
17339 this.nesting = nesting;
17341 AST_Scope.DEFMETHOD("strict", function() {
17342 return this.has_directive("use strict");
17344 AST_Lambda.DEFMETHOD("init_scope_vars", function() {
17345 AST_Scope.prototype.init_scope_vars.apply(this, arguments);
17346 this.uses_arguments = false;
17348 AST_SymbolRef.DEFMETHOD("reference", function() {
17349 var def = this.definition();
17350 def.references.push(this);
17351 var s = this.scope;
17353 push_uniq(s.enclosed, def);
17354 if (s === def.scope) break;
17355 s = s.parent_scope;
17357 this.frame = this.scope.nesting - def.scope.nesting;
17359 AST_Label.DEFMETHOD("init_scope_vars", function() {
17360 this.references = [];
17362 AST_LabelRef.DEFMETHOD("reference", function() {
17363 this.thedef.references.push(this);
17365 AST_Scope.DEFMETHOD("find_variable", function(name) {
17366 if (name instanceof AST_Symbol) name = name.name;
17367 return this.variables.get(name) || this.parent_scope && this.parent_scope.find_variable(name);
17369 AST_Scope.DEFMETHOD("has_directive", function(value) {
17370 return this.parent_scope && this.parent_scope.has_directive(value) || (this.directives.indexOf(value) >= 0 ? this : null);
17372 AST_Scope.DEFMETHOD("def_function", function(symbol) {
17373 this.functions.set(symbol.name, this.def_variable(symbol));
17375 AST_Scope.DEFMETHOD("def_variable", function(symbol) {
17377 if (!this.variables.has(symbol.name)) {
17378 def = new SymbolDef(this, this.variables.size(), symbol);
17379 this.variables.set(symbol.name, def);
17380 def.global = !this.parent_scope;
17382 def = this.variables.get(symbol.name);
17383 def.orig.push(symbol);
17385 return symbol.thedef = def;
17387 AST_Scope.DEFMETHOD("next_mangled", function(options) {
17388 var ext = this.enclosed;
17389 out: while (true) {
17390 var m = base54(++this.cname);
17391 if (!is_identifier(m)) continue;
17392 for (var i = ext.length; --i >= 0; ) {
17394 var name = sym.mangled_name || sym.unmangleable(options) && sym.name;
17395 if (m == name) continue out;
17400 AST_Scope.DEFMETHOD("references", function(sym) {
17401 if (sym instanceof AST_Symbol) sym = sym.definition();
17402 return this.enclosed.indexOf(sym) < 0 ? null : sym;
17404 AST_Symbol.DEFMETHOD("unmangleable", function(options) {
17405 return this.definition().unmangleable(options);
17407 AST_SymbolAccessor.DEFMETHOD("unmangleable", function() {
17410 AST_Label.DEFMETHOD("unmangleable", function() {
17413 AST_Symbol.DEFMETHOD("unreferenced", function() {
17414 return this.definition().references.length == 0 && !(this.scope.uses_eval || this.scope.uses_with);
17416 AST_Symbol.DEFMETHOD("undeclared", function() {
17417 return this.definition().undeclared;
17419 AST_LabelRef.DEFMETHOD("undeclared", function() {
17422 AST_Label.DEFMETHOD("undeclared", function() {
17425 AST_Symbol.DEFMETHOD("definition", function() {
17426 return this.thedef;
17428 AST_Symbol.DEFMETHOD("global", function() {
17429 return this.definition().global;
17431 AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
17432 return defaults(options, {
17440 AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
17441 options = this._default_mangler_options(options);
17443 var to_mangle = [];
17444 var tw = new TreeWalker(function(node, descend) {
17445 if (node instanceof AST_LabeledStatement) {
17446 var save_nesting = lname;
17448 lname = save_nesting;
17451 if (node instanceof AST_Scope) {
17452 var p = tw.parent(), a = [];
17453 node.variables.each(function(symbol) {
17454 if (options.except.indexOf(symbol.name) < 0) {
17458 if (options.sort) a.sort(function(a, b) {
17459 return b.references.length - a.references.length;
17461 to_mangle.push.apply(to_mangle, a);
17464 if (node instanceof AST_Label) {
17466 do name = base54(++lname); while (!is_identifier(name));
17467 node.mangled_name = name;
17472 to_mangle.forEach(function(def) {
17473 def.mangle(options);
17476 AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
17477 options = this._default_mangler_options(options);
17478 var tw = new TreeWalker(function(node) {
17479 if (node instanceof AST_Constant) base54.consider(node.print_to_string()); else if (node instanceof AST_Return) base54.consider("return"); else if (node instanceof AST_Throw) base54.consider("throw"); else if (node instanceof AST_Continue) base54.consider("continue"); else if (node instanceof AST_Break) base54.consider("break"); else if (node instanceof AST_Debugger) base54.consider("debugger"); else if (node instanceof AST_Directive) base54.consider(node.value); else if (node instanceof AST_While) base54.consider("while"); else if (node instanceof AST_Do) base54.consider("do while"); else if (node instanceof AST_If) {
17480 base54.consider("if");
17481 if (node.alternative) base54.consider("else");
17482 } else if (node instanceof AST_Var) base54.consider("var"); else if (node instanceof AST_Const) base54.consider("const"); else if (node instanceof AST_Lambda) base54.consider("function"); else if (node instanceof AST_For) base54.consider("for"); else if (node instanceof AST_ForIn) base54.consider("for in"); else if (node instanceof AST_Switch) base54.consider("switch"); else if (node instanceof AST_Case) base54.consider("case"); else if (node instanceof AST_Default) base54.consider("default"); else if (node instanceof AST_With) base54.consider("with"); else if (node instanceof AST_ObjectSetter) base54.consider("set" + node.key); else if (node instanceof AST_ObjectGetter) base54.consider("get" + node.key); else if (node instanceof AST_ObjectKeyVal) base54.consider(node.key); else if (node instanceof AST_New) base54.consider("new"); else if (node instanceof AST_This) base54.consider("this"); else if (node instanceof AST_Try) base54.consider("try"); else if (node instanceof AST_Catch) base54.consider("catch"); else if (node instanceof AST_Finally) base54.consider("finally"); else if (node instanceof AST_Symbol && node.unmangleable(options)) base54.consider(node.name); else if (node instanceof AST_Unary || node instanceof AST_Binary) base54.consider(node.operator); else if (node instanceof AST_Dot) base54.consider(node.property);
17487 var base54 = function() {
17488 var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
17489 var chars, frequency;
17491 frequency = Object.create(null);
17492 chars = string.split("").map(function(ch) {
17493 return ch.charCodeAt(0);
17495 chars.forEach(function(ch) {
17499 base54.consider = function(str) {
17500 for (var i = str.length; --i >= 0; ) {
17501 var code = str.charCodeAt(i);
17502 if (code in frequency) ++frequency[code];
17505 base54.sort = function() {
17506 chars = mergeSort(chars, function(a, b) {
17507 if (is_digit(a) && !is_digit(b)) return 1;
17508 if (is_digit(b) && !is_digit(a)) return -1;
17509 return frequency[b] - frequency[a];
17512 base54.reset = reset;
17514 base54.get = function() {
17517 base54.freq = function() {
17520 function base54(num) {
17521 var ret = "", base = 54;
17523 ret += String.fromCharCode(chars[num % base]);
17524 num = Math.floor(num / base);
17531 AST_Toplevel.DEFMETHOD("scope_warnings", function(options) {
17532 options = defaults(options, {
17534 unreferenced: true,
17535 assign_to_global: true,
17536 func_arguments: true,
17537 nested_defuns: true,
17540 var tw = new TreeWalker(function(node) {
17541 if (options.undeclared && node instanceof AST_SymbolRef && node.undeclared()) {
17542 AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
17544 file: node.start.file,
17545 line: node.start.line,
17546 col: node.start.col
17549 if (options.assign_to_global) {
17551 if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) sym = node.left; else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) sym = node.init;
17552 if (sym && (sym.undeclared() || sym.global() && sym.scope !== sym.definition().scope)) {
17553 AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
17554 msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
17556 file: sym.start.file,
17557 line: sym.start.line,
17562 if (options.eval && node instanceof AST_SymbolRef && node.undeclared() && node.name == "eval") {
17563 AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
17565 if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) && node.unreferenced()) {
17566 AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
17567 type: node instanceof AST_Label ? "Label" : "Symbol",
17569 file: node.start.file,
17570 line: node.start.line,
17571 col: node.start.col
17574 if (options.func_arguments && node instanceof AST_Lambda && node.uses_arguments) {
17575 AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
17576 name: node.name ? node.name.name : "anonymous",
17577 file: node.start.file,
17578 line: node.start.line,
17579 col: node.start.col
17582 if (options.nested_defuns && node instanceof AST_Defun && !(tw.parent() instanceof AST_Scope)) {
17583 AST_Node.warn('Function {name} declared in nested statement "{type}" [{file}:{line},{col}]', {
17584 name: node.name.name,
17585 type: tw.parent().TYPE,
17586 file: node.start.file,
17587 line: node.start.line,
17588 col: node.start.col
17595 function OutputStream(options) {
17596 options = defaults(options, {
17602 inline_script: false,
17604 max_line_len: 32e3,
17611 preserve_line: false,
17612 negate_iife: !(options && options.beautify)
17614 var indentation = 0;
17615 var current_col = 0;
17616 var current_line = 1;
17617 var current_pos = 0;
17619 function to_ascii(str, identifier) {
17620 return str.replace(/[\u0080-\uffff]/g, function(ch) {
17621 var code = ch.charCodeAt(0).toString(16);
17622 if (code.length <= 2 && !identifier) {
17623 while (code.length < 2) code = "0" + code;
17624 return "\\x" + code;
17626 while (code.length < 4) code = "0" + code;
17627 return "\\u" + code;
17631 function make_string(str) {
17632 var dq = 0, sq = 0;
17633 str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s) {
17669 if (options.ascii_only) str = to_ascii(str);
17670 if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; else return '"' + str.replace(/\x22/g, '\\"') + '"';
17672 function encode_string(str) {
17673 var ret = make_string(str);
17674 if (options.inline_script) ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
17677 function make_name(name) {
17678 name = name.toString();
17679 if (options.ascii_only) name = to_ascii(name, true);
17682 function make_indent(back) {
17683 return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
17685 var might_need_space = false;
17686 var might_need_semicolon = false;
17688 function last_char() {
17689 return last.charAt(last.length - 1);
17691 function maybe_newline() {
17692 if (options.max_line_len && current_col > options.max_line_len) print("\n");
17694 var requireSemicolonChars = makePredicate("( [ + * / - , .");
17695 function print(str) {
17697 var ch = str.charAt(0);
17698 if (might_need_semicolon) {
17699 if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
17700 if (options.semicolons || requireSemicolonChars(ch)) {
17710 if (!options.beautify) might_need_space = false;
17712 might_need_semicolon = false;
17715 if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
17716 var target_line = stack[stack.length - 1].start.line;
17717 while (current_line < target_line) {
17722 might_need_space = false;
17725 if (might_need_space) {
17726 var prev = last_char();
17727 if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\") || /^[\+\-\/]$/.test(ch) && ch == prev) {
17732 might_need_space = false;
17734 var a = str.split(/\r?\n/), n = a.length - 1;
17737 current_col += a[n].length;
17739 current_col = a[n].length;
17741 current_pos += str.length;
17745 var space = options.beautify ? function() {
17748 might_need_space = true;
17750 var indent = options.beautify ? function(half) {
17751 if (options.beautify) {
17752 print(make_indent(half ? .5 : 0));
17755 var with_indent = options.beautify ? function(col, cont) {
17756 if (col === true) col = next_indent();
17757 var save_indentation = indentation;
17760 indentation = save_indentation;
17762 } : function(col, cont) {
17765 var newline = options.beautify ? function() {
17768 var semicolon = options.beautify ? function() {
17771 might_need_semicolon = true;
17773 function force_semicolon() {
17774 might_need_semicolon = false;
17777 function next_indent() {
17778 return indentation + options.indent_level;
17780 function with_block(cont) {
17784 with_indent(next_indent(), function() {
17791 function with_parens(cont) {
17797 function with_square(cont) {
17809 if (options.space_colon) space();
17811 var add_mapping = options.source_map ? function(token, name) {
17813 if (token) options.source_map.add(token.file || "?", current_line, current_col, token.line, token.col, !name && token.type == "name" ? token.value : name);
17815 AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
17819 cline: current_line,
17833 indentation: function() {
17834 return indentation;
17836 current_width: function() {
17837 return current_col - indentation;
17839 should_break: function() {
17840 return options.width && this.current_width() >= options.width;
17850 semicolon: semicolon,
17851 force_semicolon: force_semicolon,
17852 to_ascii: to_ascii,
17853 print_name: function(name) {
17854 print(make_name(name));
17856 print_string: function(str) {
17857 print(encode_string(str));
17859 next_indent: next_indent,
17860 with_indent: with_indent,
17861 with_block: with_block,
17862 with_parens: with_parens,
17863 with_square: with_square,
17864 add_mapping: add_mapping,
17865 option: function(opt) {
17866 return options[opt];
17869 return current_line;
17872 return current_col;
17875 return current_pos;
17877 push_node: function(node) {
17880 pop_node: function() {
17881 return stack.pop();
17883 stack: function() {
17886 parent: function(n) {
17887 return stack[stack.length - 2 - (n || 0)];
17892 function DEFPRINT(nodetype, generator) {
17893 nodetype.DEFMETHOD("_codegen", generator);
17895 AST_Node.DEFMETHOD("print", function(stream, force_parens) {
17896 var self = this, generator = self._codegen;
17897 stream.push_node(self);
17898 var needs_parens = self.needs_parens(stream);
17899 var fc = self instanceof AST_Function && stream.option("negate_iife");
17900 if (force_parens || needs_parens && !fc) {
17901 stream.with_parens(function() {
17902 self.add_comments(stream);
17903 self.add_source_map(stream);
17904 generator(self, stream);
17907 self.add_comments(stream);
17908 if (needs_parens && fc) stream.print("!");
17909 self.add_source_map(stream);
17910 generator(self, stream);
17914 AST_Node.DEFMETHOD("print_to_string", function(options) {
17915 var s = OutputStream(options);
17919 AST_Node.DEFMETHOD("add_comments", function(output) {
17920 var c = output.option("comments"), self = this;
17922 var start = self.start;
17923 if (start && !start._comments_dumped) {
17924 start._comments_dumped = true;
17925 var comments = start.comments_before;
17926 if (self instanceof AST_Exit && self.value && self.value.start.comments_before.length > 0) {
17927 comments = (comments || []).concat(self.value.start.comments_before);
17928 self.value.start.comments_before = [];
17931 comments = comments.filter(function(comment) {
17932 return c.test(comment.value);
17934 } else if (typeof c == "function") {
17935 comments = comments.filter(function(comment) {
17936 return c(self, comment);
17939 comments.forEach(function(c) {
17940 if (c.type == "comment1") {
17941 output.print("//" + c.value + "\n");
17943 } else if (c.type == "comment2") {
17944 output.print("/*" + c.value + "*/");
17946 output.print("\n");
17956 function PARENS(nodetype, func) {
17957 nodetype.DEFMETHOD("needs_parens", func);
17959 PARENS(AST_Node, function() {
17962 PARENS(AST_Function, function(output) {
17963 return first_in_statement(output);
17965 PARENS(AST_Object, function(output) {
17966 return first_in_statement(output);
17968 PARENS(AST_Unary, function(output) {
17969 var p = output.parent();
17970 return p instanceof AST_PropAccess && p.expression === this;
17972 PARENS(AST_Seq, function(output) {
17973 var p = output.parent();
17974 return p instanceof AST_Call || p instanceof AST_Unary || p instanceof AST_Binary || p instanceof AST_VarDef || p instanceof AST_Dot || p instanceof AST_Array || p instanceof AST_ObjectProperty || p instanceof AST_Conditional;
17976 PARENS(AST_Binary, function(output) {
17977 var p = output.parent();
17978 if (p instanceof AST_Call && p.expression === this) return true;
17979 if (p instanceof AST_Unary) return true;
17980 if (p instanceof AST_PropAccess && p.expression === this) return true;
17981 if (p instanceof AST_Binary) {
17982 var po = p.operator, pp = PRECEDENCE[po];
17983 var so = this.operator, sp = PRECEDENCE[so];
17984 if (pp > sp || pp == sp && this === p.right && !(so == po && (so == "*" || so == "&&" || so == "||"))) {
17989 PARENS(AST_PropAccess, function(output) {
17990 var p = output.parent();
17991 if (p instanceof AST_New && p.expression === this) {
17993 this.walk(new TreeWalker(function(node) {
17994 if (node instanceof AST_Call) throw p;
17997 if (ex !== p) throw ex;
18002 PARENS(AST_Call, function(output) {
18003 var p = output.parent();
18004 return p instanceof AST_New && p.expression === this;
18006 PARENS(AST_New, function(output) {
18007 var p = output.parent();
18008 if (no_constructor_parens(this, output) && (p instanceof AST_PropAccess || p instanceof AST_Call && p.expression === this)) return true;
18010 PARENS(AST_Number, function(output) {
18011 var p = output.parent();
18012 if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) return true;
18014 PARENS(AST_NaN, function(output) {
18015 var p = output.parent();
18016 if (p instanceof AST_PropAccess && p.expression === this) return true;
18018 function assign_and_conditional_paren_rules(output) {
18019 var p = output.parent();
18020 if (p instanceof AST_Unary) return true;
18021 if (p instanceof AST_Binary && !(p instanceof AST_Assign)) return true;
18022 if (p instanceof AST_Call && p.expression === this) return true;
18023 if (p instanceof AST_Conditional && p.condition === this) return true;
18024 if (p instanceof AST_PropAccess && p.expression === this) return true;
18026 PARENS(AST_Assign, assign_and_conditional_paren_rules);
18027 PARENS(AST_Conditional, assign_and_conditional_paren_rules);
18028 DEFPRINT(AST_Directive, function(self, output) {
18029 output.print_string(self.value);
18030 output.semicolon();
18032 DEFPRINT(AST_Debugger, function(self, output) {
18033 output.print("debugger");
18034 output.semicolon();
18036 function display_body(body, is_toplevel, output) {
18037 var last = body.length - 1;
18038 body.forEach(function(stmt, i) {
18039 if (!(stmt instanceof AST_EmptyStatement)) {
18041 stmt.print(output);
18042 if (!(i == last && is_toplevel)) {
18044 if (is_toplevel) output.newline();
18049 AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
18050 force_statement(this.body, output);
18052 DEFPRINT(AST_Statement, function(self, output) {
18053 self.body.print(output);
18054 output.semicolon();
18056 DEFPRINT(AST_Toplevel, function(self, output) {
18057 display_body(self.body, true, output);
18060 DEFPRINT(AST_LabeledStatement, function(self, output) {
18061 self.label.print(output);
18063 self.body.print(output);
18065 DEFPRINT(AST_SimpleStatement, function(self, output) {
18066 self.body.print(output);
18067 output.semicolon();
18069 function print_bracketed(body, output) {
18070 if (body.length > 0) output.with_block(function() {
18071 display_body(body, false, output);
18072 }); else output.print("{}");
18074 DEFPRINT(AST_BlockStatement, function(self, output) {
18075 print_bracketed(self.body, output);
18077 DEFPRINT(AST_EmptyStatement, function(self, output) {
18078 output.semicolon();
18080 DEFPRINT(AST_Do, function(self, output) {
18081 output.print("do");
18083 self._do_print_body(output);
18085 output.print("while");
18087 output.with_parens(function() {
18088 self.condition.print(output);
18090 output.semicolon();
18092 DEFPRINT(AST_While, function(self, output) {
18093 output.print("while");
18095 output.with_parens(function() {
18096 self.condition.print(output);
18099 self._do_print_body(output);
18101 DEFPRINT(AST_For, function(self, output) {
18102 output.print("for");
18104 output.with_parens(function() {
18106 if (self.init instanceof AST_Definitions) {
18107 self.init.print(output);
18109 parenthesize_for_noin(self.init, output, true);
18116 if (self.condition) {
18117 self.condition.print(output);
18124 self.step.print(output);
18128 self._do_print_body(output);
18130 DEFPRINT(AST_ForIn, function(self, output) {
18131 output.print("for");
18133 output.with_parens(function() {
18134 self.init.print(output);
18136 output.print("in");
18138 self.object.print(output);
18141 self._do_print_body(output);
18143 DEFPRINT(AST_With, function(self, output) {
18144 output.print("with");
18146 output.with_parens(function() {
18147 self.expression.print(output);
18150 self._do_print_body(output);
18152 AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
18155 output.print("function");
18159 self.name.print(output);
18161 output.with_parens(function() {
18162 self.argnames.forEach(function(arg, i) {
18163 if (i) output.comma();
18168 print_bracketed(self.body, output);
18170 DEFPRINT(AST_Lambda, function(self, output) {
18171 self._do_print(output);
18173 AST_Exit.DEFMETHOD("_do_print", function(output, kind) {
18174 output.print(kind);
18177 this.value.print(output);
18179 output.semicolon();
18181 DEFPRINT(AST_Return, function(self, output) {
18182 self._do_print(output, "return");
18184 DEFPRINT(AST_Throw, function(self, output) {
18185 self._do_print(output, "throw");
18187 AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) {
18188 output.print(kind);
18191 this.label.print(output);
18193 output.semicolon();
18195 DEFPRINT(AST_Break, function(self, output) {
18196 self._do_print(output, "break");
18198 DEFPRINT(AST_Continue, function(self, output) {
18199 self._do_print(output, "continue");
18201 function make_then(self, output) {
18202 if (output.option("bracketize")) {
18203 make_block(self.body, output);
18206 if (!self.body) return output.force_semicolon();
18207 if (self.body instanceof AST_Do && output.option("ie_proof")) {
18208 make_block(self.body, output);
18213 if (b instanceof AST_If) {
18214 if (!b.alternative) {
18215 make_block(self.body, output);
18219 } else if (b instanceof AST_StatementWithBody) {
18223 force_statement(self.body, output);
18225 DEFPRINT(AST_If, function(self, output) {
18226 output.print("if");
18228 output.with_parens(function() {
18229 self.condition.print(output);
18232 if (self.alternative) {
18233 make_then(self, output);
18235 output.print("else");
18237 force_statement(self.alternative, output);
18239 self._do_print_body(output);
18242 DEFPRINT(AST_Switch, function(self, output) {
18243 output.print("switch");
18245 output.with_parens(function() {
18246 self.expression.print(output);
18249 if (self.body.length > 0) output.with_block(function() {
18250 self.body.forEach(function(stmt, i) {
18251 if (i) output.newline();
18252 output.indent(true);
18253 stmt.print(output);
18255 }); else output.print("{}");
18257 AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
18258 if (this.body.length > 0) {
18260 this.body.forEach(function(stmt) {
18262 stmt.print(output);
18267 DEFPRINT(AST_Default, function(self, output) {
18268 output.print("default:");
18269 self._do_print_body(output);
18271 DEFPRINT(AST_Case, function(self, output) {
18272 output.print("case");
18274 self.expression.print(output);
18276 self._do_print_body(output);
18278 DEFPRINT(AST_Try, function(self, output) {
18279 output.print("try");
18281 print_bracketed(self.body, output);
18284 self.bcatch.print(output);
18286 if (self.bfinally) {
18288 self.bfinally.print(output);
18291 DEFPRINT(AST_Catch, function(self, output) {
18292 output.print("catch");
18294 output.with_parens(function() {
18295 self.argname.print(output);
18298 print_bracketed(self.body, output);
18300 DEFPRINT(AST_Finally, function(self, output) {
18301 output.print("finally");
18303 print_bracketed(self.body, output);
18305 AST_Definitions.DEFMETHOD("_do_print", function(output, kind) {
18306 output.print(kind);
18308 this.definitions.forEach(function(def, i) {
18309 if (i) output.comma();
18312 var p = output.parent();
18313 var in_for = p instanceof AST_For || p instanceof AST_ForIn;
18314 var avoid_semicolon = in_for && p.init === this;
18315 if (!avoid_semicolon) output.semicolon();
18317 DEFPRINT(AST_Var, function(self, output) {
18318 self._do_print(output, "var");
18320 DEFPRINT(AST_Const, function(self, output) {
18321 self._do_print(output, "const");
18323 function parenthesize_for_noin(node, output, noin) {
18324 if (!noin) node.print(output); else try {
18325 node.walk(new TreeWalker(function(node) {
18326 if (node instanceof AST_Binary && node.operator == "in") throw output;
18328 node.print(output);
18330 if (ex !== output) throw ex;
18331 node.print(output, true);
18334 DEFPRINT(AST_VarDef, function(self, output) {
18335 self.name.print(output);
18340 var p = output.parent(1);
18341 var noin = p instanceof AST_For || p instanceof AST_ForIn;
18342 parenthesize_for_noin(self.value, output, noin);
18345 DEFPRINT(AST_Call, function(self, output) {
18346 self.expression.print(output);
18347 if (self instanceof AST_New && no_constructor_parens(self, output)) return;
18348 output.with_parens(function() {
18349 self.args.forEach(function(expr, i) {
18350 if (i) output.comma();
18351 expr.print(output);
18355 DEFPRINT(AST_New, function(self, output) {
18356 output.print("new");
18358 AST_Call.prototype._codegen(self, output);
18360 AST_Seq.DEFMETHOD("_do_print", function(output) {
18361 this.car.print(output);
18364 if (output.should_break()) {
18368 this.cdr.print(output);
18371 DEFPRINT(AST_Seq, function(self, output) {
18372 self._do_print(output);
18374 DEFPRINT(AST_Dot, function(self, output) {
18375 var expr = self.expression;
18376 expr.print(output);
18377 if (expr instanceof AST_Number && expr.getValue() >= 0) {
18378 if (!/[xa-f.]/i.test(output.last())) {
18383 output.add_mapping(self.end);
18384 output.print_name(self.property);
18386 DEFPRINT(AST_Sub, function(self, output) {
18387 self.expression.print(output);
18389 self.property.print(output);
18392 DEFPRINT(AST_UnaryPrefix, function(self, output) {
18393 var op = self.operator;
18395 if (/^[a-z]/i.test(op)) output.space();
18396 self.expression.print(output);
18398 DEFPRINT(AST_UnaryPostfix, function(self, output) {
18399 self.expression.print(output);
18400 output.print(self.operator);
18402 DEFPRINT(AST_Binary, function(self, output) {
18403 self.left.print(output);
18405 output.print(self.operator);
18407 self.right.print(output);
18409 DEFPRINT(AST_Conditional, function(self, output) {
18410 self.condition.print(output);
18414 self.consequent.print(output);
18417 self.alternative.print(output);
18419 DEFPRINT(AST_Array, function(self, output) {
18420 output.with_square(function() {
18421 var a = self.elements, len = a.length;
18422 if (len > 0) output.space();
18423 a.forEach(function(exp, i) {
18424 if (i) output.comma();
18427 if (len > 0) output.space();
18430 DEFPRINT(AST_Object, function(self, output) {
18431 if (self.properties.length > 0) output.with_block(function() {
18432 self.properties.forEach(function(prop, i) {
18438 prop.print(output);
18441 }); else output.print("{}");
18443 DEFPRINT(AST_ObjectKeyVal, function(self, output) {
18444 var key = self.key;
18445 if (output.option("quote_keys")) {
18446 output.print_string(key + "");
18447 } else if ((typeof key == "number" || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) {
18448 output.print(make_num(key));
18449 } else if (!is_identifier(key)) {
18450 output.print_string(key);
18452 output.print_name(key);
18455 self.value.print(output);
18457 DEFPRINT(AST_ObjectSetter, function(self, output) {
18458 output.print("set");
18459 self.value._do_print(output, true);
18461 DEFPRINT(AST_ObjectGetter, function(self, output) {
18462 output.print("get");
18463 self.value._do_print(output, true);
18465 DEFPRINT(AST_Symbol, function(self, output) {
18466 var def = self.definition();
18467 output.print_name(def ? def.mangled_name || def.name : self.name);
18469 DEFPRINT(AST_Undefined, function(self, output) {
18470 output.print("void 0");
18472 DEFPRINT(AST_Hole, noop);
18473 DEFPRINT(AST_Infinity, function(self, output) {
18474 output.print("1/0");
18476 DEFPRINT(AST_NaN, function(self, output) {
18477 output.print("0/0");
18479 DEFPRINT(AST_This, function(self, output) {
18480 output.print("this");
18482 DEFPRINT(AST_Constant, function(self, output) {
18483 output.print(self.getValue());
18485 DEFPRINT(AST_String, function(self, output) {
18486 output.print_string(self.getValue());
18488 DEFPRINT(AST_Number, function(self, output) {
18489 output.print(make_num(self.getValue()));
18491 DEFPRINT(AST_RegExp, function(self, output) {
18492 var str = self.getValue().toString();
18493 if (output.option("ascii_only")) str = output.to_ascii(str);
18495 var p = output.parent();
18496 if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) output.print(" ");
18498 function force_statement(stat, output) {
18499 if (output.option("bracketize")) {
18500 if (!stat || stat instanceof AST_EmptyStatement) output.print("{}"); else if (stat instanceof AST_BlockStatement) stat.print(output); else output.with_block(function() {
18502 stat.print(output);
18506 if (!stat || stat instanceof AST_EmptyStatement) output.force_semicolon(); else stat.print(output);
18509 function first_in_statement(output) {
18510 var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
18512 if (p instanceof AST_Statement && p.body === node) return true;
18513 if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) {
18521 function no_constructor_parens(self, output) {
18522 return self.args.length == 0 && !output.option("beautify");
18524 function best_of(a) {
18525 var best = a[0], len = best.length;
18526 for (var i = 1; i < a.length; ++i) {
18527 if (a[i].length < len) {
18534 function make_num(num) {
18535 var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace("e+", "e") ], m;
18536 if (Math.floor(num) === num) {
18538 a.push("0x" + num.toString(16).toLowerCase(), "0" + num.toString(8));
18540 a.push("-0x" + (-num).toString(16).toLowerCase(), "-0" + (-num).toString(8));
18542 if (m = /^(.*?)(0+)$/.exec(num)) {
18543 a.push(m[1] + "e" + m[2].length);
18545 } else if (m = /^0?\.(0+)(.*)$/.exec(num)) {
18546 a.push(m[2] + "e-" + (m[1].length + m[2].length), str.substr(str.indexOf(".")));
18550 function make_block(stmt, output) {
18551 if (stmt instanceof AST_BlockStatement) {
18552 stmt.print(output);
18555 output.with_block(function() {
18557 stmt.print(output);
18561 function DEFMAP(nodetype, generator) {
18562 nodetype.DEFMETHOD("add_source_map", function(stream) {
18563 generator(this, stream);
18566 DEFMAP(AST_Node, noop);
18567 function basic_sourcemap_gen(self, output) {
18568 output.add_mapping(self.start);
18570 DEFMAP(AST_Directive, basic_sourcemap_gen);
18571 DEFMAP(AST_Debugger, basic_sourcemap_gen);
18572 DEFMAP(AST_Symbol, basic_sourcemap_gen);
18573 DEFMAP(AST_Jump, basic_sourcemap_gen);
18574 DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
18575 DEFMAP(AST_LabeledStatement, noop);
18576 DEFMAP(AST_Lambda, basic_sourcemap_gen);
18577 DEFMAP(AST_Switch, basic_sourcemap_gen);
18578 DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
18579 DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
18580 DEFMAP(AST_Toplevel, noop);
18581 DEFMAP(AST_New, basic_sourcemap_gen);
18582 DEFMAP(AST_Try, basic_sourcemap_gen);
18583 DEFMAP(AST_Catch, basic_sourcemap_gen);
18584 DEFMAP(AST_Finally, basic_sourcemap_gen);
18585 DEFMAP(AST_Definitions, basic_sourcemap_gen);
18586 DEFMAP(AST_Constant, basic_sourcemap_gen);
18587 DEFMAP(AST_ObjectProperty, function(self, output) {
18588 output.add_mapping(self.start, self.key);
18592 function Compressor(options, false_by_default) {
18593 if (!(this instanceof Compressor)) return new Compressor(options, false_by_default);
18594 TreeTransformer.call(this, this.before, this.after);
18595 this.options = defaults(options, {
18596 sequences: !false_by_default,
18597 properties: !false_by_default,
18598 dead_code: !false_by_default,
18599 drop_debugger: !false_by_default,
18601 unsafe_comps: false,
18602 conditionals: !false_by_default,
18603 comparisons: !false_by_default,
18604 evaluate: !false_by_default,
18605 booleans: !false_by_default,
18606 loops: !false_by_default,
18607 unused: !false_by_default,
18608 hoist_funs: !false_by_default,
18610 if_return: !false_by_default,
18611 join_vars: !false_by_default,
18612 cascade: !false_by_default,
18613 side_effects: !false_by_default,
18619 Compressor.prototype = new TreeTransformer();
18620 merge(Compressor.prototype, {
18621 option: function(key) {
18622 return this.options[key];
18625 if (this.options.warnings) AST_Node.warn.apply(AST_Node, arguments);
18627 before: function(node, descend, in_list) {
18628 if (node._squeezed) return node;
18629 if (node instanceof AST_Scope) {
18630 node.drop_unused(this);
18631 node = node.hoist_declarations(this);
18633 descend(node, this);
18634 node = node.optimize(this);
18635 if (node instanceof AST_Scope) {
18636 var save_warnings = this.options.warnings;
18637 this.options.warnings = false;
18638 node.drop_unused(this);
18639 this.options.warnings = save_warnings;
18641 node._squeezed = true;
18646 function OPT(node, optimizer) {
18647 node.DEFMETHOD("optimize", function(compressor) {
18649 if (self._optimized) return self;
18650 var opt = optimizer(self, compressor);
18651 opt._optimized = true;
18652 if (opt === self) return opt;
18653 return opt.transform(compressor);
18656 OPT(AST_Node, function(self, compressor) {
18659 AST_Node.DEFMETHOD("equivalent_to", function(node) {
18660 return this.print_to_string() == node.print_to_string();
18662 function make_node(ctor, orig, props) {
18663 if (!props) props = {};
18665 if (!props.start) props.start = orig.start;
18666 if (!props.end) props.end = orig.end;
18668 return new ctor(props);
18670 function make_node_from_constant(compressor, val, orig) {
18671 if (val instanceof AST_Node) return val.transform(compressor);
18672 switch (typeof val) {
18674 return make_node(AST_String, orig, {
18676 }).optimize(compressor);
18679 return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {
18681 }).optimize(compressor);
18684 return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
18687 return make_node(AST_Undefined, orig).optimize(compressor);
18690 if (val === null) {
18691 return make_node(AST_Null, orig).optimize(compressor);
18693 if (val instanceof RegExp) {
18694 return make_node(AST_RegExp, orig).optimize(compressor);
18696 throw new Error(string_template("Can't handle constant of type: {type}", {
18701 function as_statement_array(thing) {
18702 if (thing === null) return [];
18703 if (thing instanceof AST_BlockStatement) return thing.body;
18704 if (thing instanceof AST_EmptyStatement) return [];
18705 if (thing instanceof AST_Statement) return [ thing ];
18706 throw new Error("Can't convert thing to statement array");
18708 function is_empty(thing) {
18709 if (thing === null) return true;
18710 if (thing instanceof AST_EmptyStatement) return true;
18711 if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
18714 function loop_body(x) {
18715 if (x instanceof AST_Switch) return x;
18716 if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
18717 return x.body instanceof AST_BlockStatement ? x.body : x;
18721 function tighten_body(statements, compressor) {
18725 statements = eliminate_spurious_blocks(statements);
18726 if (compressor.option("dead_code")) {
18727 statements = eliminate_dead_code(statements, compressor);
18729 if (compressor.option("if_return")) {
18730 statements = handle_if_return(statements, compressor);
18732 if (compressor.option("sequences")) {
18733 statements = sequencesize(statements, compressor);
18735 if (compressor.option("join_vars")) {
18736 statements = join_consecutive_vars(statements, compressor);
18740 function eliminate_spurious_blocks(statements) {
18741 var seen_dirs = [];
18742 return statements.reduce(function(a, stat) {
18743 if (stat instanceof AST_BlockStatement) {
18745 a.push.apply(a, eliminate_spurious_blocks(stat.body));
18746 } else if (stat instanceof AST_EmptyStatement) {
18748 } else if (stat instanceof AST_Directive) {
18749 if (seen_dirs.indexOf(stat.value) < 0) {
18751 seen_dirs.push(stat.value);
18761 function handle_if_return(statements, compressor) {
18762 var self = compressor.self();
18763 var in_lambda = self instanceof AST_Lambda;
18765 loop: for (var i = statements.length; --i >= 0; ) {
18766 var stat = statements[i];
18768 case in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0:
18772 case stat instanceof AST_If:
18773 if (stat.body instanceof AST_Return) {
18774 if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value) && !stat.body.value && !stat.alternative) {
18776 var cond = make_node(AST_SimpleStatement, stat.condition, {
18777 body: stat.condition
18782 if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
18784 stat = stat.clone();
18785 stat.alternative = ret[0];
18786 ret[0] = stat.transform(compressor);
18789 if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {
18791 stat = stat.clone();
18792 stat.alternative = ret[0] || make_node(AST_Return, stat, {
18793 value: make_node(AST_Undefined, stat)
18795 ret[0] = stat.transform(compressor);
18798 if (!stat.body.value && in_lambda) {
18800 stat = stat.clone();
18801 stat.condition = stat.condition.negate(compressor);
18802 stat.body = make_node(AST_BlockStatement, stat, {
18803 body: as_statement_array(stat.alternative).concat(ret)
18805 stat.alternative = null;
18806 ret = [ stat.transform(compressor) ];
18809 if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
18811 ret.push(make_node(AST_Return, ret[0], {
18812 value: make_node(AST_Undefined, ret[0])
18813 }).transform(compressor));
18814 ret = as_statement_array(stat.alternative).concat(ret);
18819 var ab = aborts(stat.body);
18820 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
18821 if (ab && (ab instanceof AST_Return && !ab.value && in_lambda || ab instanceof AST_Continue && self === loop_body(lct) || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct)) {
18823 remove(ab.label.thedef.references, ab.label);
18826 var body = as_statement_array(stat.body).slice(0, -1);
18827 stat = stat.clone();
18828 stat.condition = stat.condition.negate(compressor);
18829 stat.body = make_node(AST_BlockStatement, stat, {
18832 stat.alternative = make_node(AST_BlockStatement, stat, {
18835 ret = [ stat.transform(compressor) ];
18838 var ab = aborts(stat.alternative);
18839 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
18840 if (ab && (ab instanceof AST_Return && !ab.value && in_lambda || ab instanceof AST_Continue && self === loop_body(lct) || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct)) {
18842 remove(ab.label.thedef.references, ab.label);
18845 stat = stat.clone();
18846 stat.body = make_node(AST_BlockStatement, stat.body, {
18847 body: as_statement_array(stat.body).concat(ret)
18849 stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
18850 body: as_statement_array(stat.alternative).slice(0, -1)
18852 ret = [ stat.transform(compressor) ];
18865 function eliminate_dead_code(statements, compressor) {
18866 var has_quit = false;
18867 var orig = statements.length;
18868 var self = compressor.self();
18869 statements = statements.reduce(function(a, stat) {
18871 extract_declarations_from_unreachable_code(compressor, stat, a);
18873 if (stat instanceof AST_LoopControl) {
18874 var lct = compressor.loopcontrol_target(stat.label);
18875 if (stat instanceof AST_Break && lct instanceof AST_BlockStatement && loop_body(lct) === self || stat instanceof AST_Continue && loop_body(lct) === self) {
18877 remove(stat.label.thedef.references, stat.label);
18885 if (aborts(stat)) has_quit = true;
18889 CHANGED = statements.length != orig;
18892 function sequencesize(statements, compressor) {
18893 if (statements.length < 2) return statements;
18894 var seq = [], ret = [];
18895 function push_seq() {
18896 seq = AST_Seq.from_array(seq);
18897 if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
18902 statements.forEach(function(stat) {
18903 if (stat instanceof AST_SimpleStatement) seq.push(stat.body); else push_seq(), ret.push(stat);
18906 ret = sequencesize_2(ret, compressor);
18907 CHANGED = ret.length != statements.length;
18910 function sequencesize_2(statements, compressor) {
18911 function cons_seq(right) {
18913 var left = prev.body;
18914 if (left instanceof AST_Seq) {
18917 left = AST_Seq.cons(left, right);
18919 return left.transform(compressor);
18921 var ret = [], prev = null;
18922 statements.forEach(function(stat) {
18924 if (stat instanceof AST_For) {
18927 prev.body.walk(new TreeWalker(function(node) {
18928 if (node instanceof AST_Binary && node.operator == "in") throw opera;
18930 if (stat.init && !(stat.init instanceof AST_Definitions)) {
18931 stat.init = cons_seq(stat.init);
18932 } else if (!stat.init) {
18933 stat.init = prev.body;
18937 if (ex !== opera) throw ex;
18939 } else if (stat instanceof AST_If) {
18940 stat.condition = cons_seq(stat.condition);
18941 } else if (stat instanceof AST_With) {
18942 stat.expression = cons_seq(stat.expression);
18943 } else if (stat instanceof AST_Exit && stat.value) {
18944 stat.value = cons_seq(stat.value);
18945 } else if (stat instanceof AST_Exit) {
18946 stat.value = cons_seq(make_node(AST_Undefined, stat));
18947 } else if (stat instanceof AST_Switch) {
18948 stat.expression = cons_seq(stat.expression);
18952 prev = stat instanceof AST_SimpleStatement ? stat : null;
18956 function join_consecutive_vars(statements, compressor) {
18958 return statements.reduce(function(a, stat) {
18959 if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
18960 prev.definitions = prev.definitions.concat(stat.definitions);
18962 } else if (stat instanceof AST_For && prev instanceof AST_Definitions && (!stat.init || stat.init.TYPE == prev.TYPE)) {
18966 stat.init.definitions = prev.definitions.concat(stat.init.definitions);
18980 function extract_declarations_from_unreachable_code(compressor, stat, target) {
18981 compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
18982 stat.walk(new TreeWalker(function(node) {
18983 if (node instanceof AST_Definitions) {
18984 compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
18985 node.remove_initializers();
18989 if (node instanceof AST_Defun) {
18993 if (node instanceof AST_Scope) {
18999 var unary_bool = [ "!", "delete" ];
19000 var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
19001 def(AST_Node, function() {
19004 def(AST_UnaryPrefix, function() {
19005 return member(this.operator, unary_bool);
19007 def(AST_Binary, function() {
19008 return member(this.operator, binary_bool) || (this.operator == "&&" || this.operator == "||") && this.left.is_boolean() && this.right.is_boolean();
19010 def(AST_Conditional, function() {
19011 return this.consequent.is_boolean() && this.alternative.is_boolean();
19013 def(AST_Assign, function() {
19014 return this.operator == "=" && this.right.is_boolean();
19016 def(AST_Seq, function() {
19017 return this.cdr.is_boolean();
19019 def(AST_True, function() {
19022 def(AST_False, function() {
19025 })(function(node, func) {
19026 node.DEFMETHOD("is_boolean", func);
19029 def(AST_Node, function() {
19032 def(AST_String, function() {
19035 def(AST_UnaryPrefix, function() {
19036 return this.operator == "typeof";
19038 def(AST_Binary, function(compressor) {
19039 return this.operator == "+" && (this.left.is_string(compressor) || this.right.is_string(compressor));
19041 def(AST_Assign, function(compressor) {
19042 return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
19044 def(AST_Seq, function(compressor) {
19045 return this.cdr.is_string(compressor);
19047 def(AST_Conditional, function(compressor) {
19048 return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
19050 def(AST_Call, function(compressor) {
19051 return compressor.option("unsafe") && this.expression instanceof AST_SymbolRef && this.expression.name == "String" && this.expression.undeclared();
19053 })(function(node, func) {
19054 node.DEFMETHOD("is_string", func);
19056 function best_of(ast1, ast2) {
19057 return ast1.print_to_string().length > ast2.print_to_string().length ? ast2 : ast1;
19060 AST_Node.DEFMETHOD("evaluate", function(compressor) {
19061 if (!compressor.option("evaluate")) return [ this ];
19063 var val = this._eval(), ast = make_node_from_constant(compressor, val, this);
19064 return [ best_of(ast, this), val ];
19066 if (ex !== def) throw ex;
19070 def(AST_Statement, function() {
19071 throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
19073 def(AST_Function, function() {
19076 function ev(node) {
19077 return node._eval();
19079 def(AST_Node, function() {
19082 def(AST_Constant, function() {
19083 return this.getValue();
19085 def(AST_UnaryPrefix, function() {
19086 var e = this.expression;
19087 switch (this.operator) {
19092 if (e instanceof AST_Function) return typeof function() {};
19094 if (e instanceof RegExp) throw def;
19105 if (e === 0) throw def;
19113 def(AST_Binary, function() {
19114 var left = this.left, right = this.right;
19115 switch (this.operator) {
19117 return ev(left) && ev(right);
19120 return ev(left) || ev(right);
19123 return ev(left) | ev(right);
19126 return ev(left) & ev(right);
19129 return ev(left) ^ ev(right);
19132 return ev(left) + ev(right);
19135 return ev(left) * ev(right);
19138 return ev(left) / ev(right);
19141 return ev(left) % ev(right);
19144 return ev(left) - ev(right);
19147 return ev(left) << ev(right);
19150 return ev(left) >> ev(right);
19153 return ev(left) >>> ev(right);
19156 return ev(left) == ev(right);
19159 return ev(left) === ev(right);
19162 return ev(left) != ev(right);
19165 return ev(left) !== ev(right);
19168 return ev(left) < ev(right);
19171 return ev(left) <= ev(right);
19174 return ev(left) > ev(right);
19177 return ev(left) >= ev(right);
19180 return ev(left) in ev(right);
19183 return ev(left) instanceof ev(right);
19187 def(AST_Conditional, function() {
19188 return ev(this.condition) ? ev(this.consequent) : ev(this.alternative);
19190 def(AST_SymbolRef, function() {
19191 var d = this.definition();
19192 if (d && d.constant && d.init) return ev(d.init);
19195 })(function(node, func) {
19196 node.DEFMETHOD("_eval", func);
19199 function basic_negation(exp) {
19200 return make_node(AST_UnaryPrefix, exp, {
19205 def(AST_Node, function() {
19206 return basic_negation(this);
19208 def(AST_Statement, function() {
19209 throw new Error("Cannot negate a statement");
19211 def(AST_Function, function() {
19212 return basic_negation(this);
19214 def(AST_UnaryPrefix, function() {
19215 if (this.operator == "!") return this.expression;
19216 return basic_negation(this);
19218 def(AST_Seq, function(compressor) {
19219 var self = this.clone();
19220 self.cdr = self.cdr.negate(compressor);
19223 def(AST_Conditional, function(compressor) {
19224 var self = this.clone();
19225 self.consequent = self.consequent.negate(compressor);
19226 self.alternative = self.alternative.negate(compressor);
19227 return best_of(basic_negation(this), self);
19229 def(AST_Binary, function(compressor) {
19230 var self = this.clone(), op = this.operator;
19231 if (compressor.option("unsafe_comps")) {
19234 self.operator = ">";
19238 self.operator = ">=";
19242 self.operator = "<";
19246 self.operator = "<=";
19252 self.operator = "!=";
19256 self.operator = "==";
19260 self.operator = "!==";
19264 self.operator = "===";
19268 self.operator = "||";
19269 self.left = self.left.negate(compressor);
19270 self.right = self.right.negate(compressor);
19271 return best_of(basic_negation(this), self);
19274 self.operator = "&&";
19275 self.left = self.left.negate(compressor);
19276 self.right = self.right.negate(compressor);
19277 return best_of(basic_negation(this), self);
19279 return basic_negation(this);
19281 })(function(node, func) {
19282 node.DEFMETHOD("negate", function(compressor) {
19283 return func.call(this, compressor);
19287 def(AST_Node, function() {
19290 def(AST_EmptyStatement, function() {
19293 def(AST_Constant, function() {
19296 def(AST_This, function() {
19299 def(AST_Block, function() {
19300 for (var i = this.body.length; --i >= 0; ) {
19301 if (this.body[i].has_side_effects()) return true;
19305 def(AST_SimpleStatement, function() {
19306 return this.body.has_side_effects();
19308 def(AST_Defun, function() {
19311 def(AST_Function, function() {
19314 def(AST_Binary, function() {
19315 return this.left.has_side_effects() || this.right.has_side_effects();
19317 def(AST_Assign, function() {
19320 def(AST_Conditional, function() {
19321 return this.condition.has_side_effects() || this.consequent.has_side_effects() || this.alternative.has_side_effects();
19323 def(AST_Unary, function() {
19324 return this.operator == "delete" || this.operator == "++" || this.operator == "--" || this.expression.has_side_effects();
19326 def(AST_SymbolRef, function() {
19329 def(AST_Object, function() {
19330 for (var i = this.properties.length; --i >= 0; ) if (this.properties[i].has_side_effects()) return true;
19333 def(AST_ObjectProperty, function() {
19334 return this.value.has_side_effects();
19336 def(AST_Array, function() {
19337 for (var i = this.elements.length; --i >= 0; ) if (this.elements[i].has_side_effects()) return true;
19340 def(AST_PropAccess, function() {
19343 def(AST_Seq, function() {
19344 return this.car.has_side_effects() || this.cdr.has_side_effects();
19346 })(function(node, func) {
19347 node.DEFMETHOD("has_side_effects", func);
19349 function aborts(thing) {
19350 return thing && thing.aborts();
19353 def(AST_Statement, function() {
19356 def(AST_Jump, function() {
19359 function block_aborts() {
19360 var n = this.body.length;
19361 return n > 0 && aborts(this.body[n - 1]);
19363 def(AST_BlockStatement, block_aborts);
19364 def(AST_SwitchBranch, block_aborts);
19365 def(AST_If, function() {
19366 return this.alternative && aborts(this.body) && aborts(this.alternative);
19368 })(function(node, func) {
19369 node.DEFMETHOD("aborts", func);
19371 OPT(AST_Directive, function(self, compressor) {
19372 if (self.scope.has_directive(self.value) !== self.scope) {
19373 return make_node(AST_EmptyStatement, self);
19377 OPT(AST_Debugger, function(self, compressor) {
19378 if (compressor.option("drop_debugger")) return make_node(AST_EmptyStatement, self);
19381 OPT(AST_LabeledStatement, function(self, compressor) {
19382 if (self.body instanceof AST_Break && compressor.loopcontrol_target(self.body.label) === self.body) {
19383 return make_node(AST_EmptyStatement, self);
19385 return self.label.references.length == 0 ? self.body : self;
19387 OPT(AST_Block, function(self, compressor) {
19388 self.body = tighten_body(self.body, compressor);
19391 OPT(AST_BlockStatement, function(self, compressor) {
19392 self.body = tighten_body(self.body, compressor);
19393 switch (self.body.length) {
19395 return self.body[0];
19398 return make_node(AST_EmptyStatement, self);
19402 AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
19404 if (compressor.option("unused") && !(self instanceof AST_Toplevel) && !self.uses_eval) {
19406 var initializations = new Dictionary();
19408 var tw = new TreeWalker(function(node, descend) {
19409 if (node !== self) {
19410 if (node instanceof AST_Defun) {
19411 initializations.add(node.name.name, node);
19414 if (node instanceof AST_Definitions && scope === self) {
19415 node.definitions.forEach(function(def) {
19417 initializations.add(def.name.name, def.value);
19418 if (def.value.has_side_effects()) {
19419 def.value.walk(tw);
19425 if (node instanceof AST_SymbolRef) {
19426 push_uniq(in_use, node.definition());
19429 if (node instanceof AST_Scope) {
19430 var save_scope = scope;
19433 scope = save_scope;
19439 for (var i = 0; i < in_use.length; ++i) {
19440 in_use[i].orig.forEach(function(decl) {
19441 var init = initializations.get(decl.name);
19442 if (init) init.forEach(function(init) {
19443 var tw = new TreeWalker(function(node) {
19444 if (node instanceof AST_SymbolRef) {
19445 push_uniq(in_use, node.definition());
19452 var tt = new TreeTransformer(function before(node, descend, in_list) {
19453 if (node instanceof AST_Lambda) {
19454 for (var a = node.argnames, i = a.length; --i >= 0; ) {
19456 if (sym.unreferenced()) {
19458 compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
19460 file: sym.start.file,
19461 line: sym.start.line,
19467 if (node instanceof AST_Defun && node !== self) {
19468 if (!member(node.name.definition(), in_use)) {
19469 compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
19470 name: node.name.name,
19471 file: node.name.start.file,
19472 line: node.name.start.line,
19473 col: node.name.start.col
19475 return make_node(AST_EmptyStatement, node);
19479 if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
19480 var def = node.definitions.filter(function(def) {
19481 if (member(def.name.definition(), in_use)) return true;
19483 name: def.name.name,
19484 file: def.name.start.file,
19485 line: def.name.start.line,
19486 col: def.name.start.col
19488 if (def.value && def.value.has_side_effects()) {
19489 def._unused_side_effects = true;
19490 compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
19493 compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w);
19496 def = mergeSort(def, function(a, b) {
19497 if (!a.value && b.value) return -1;
19498 if (!b.value && a.value) return 1;
19501 var side_effects = [];
19502 for (var i = 0; i < def.length; ) {
19504 if (x._unused_side_effects) {
19505 side_effects.push(x.value);
19508 if (side_effects.length > 0) {
19509 side_effects.push(x.value);
19510 x.value = AST_Seq.from_array(side_effects);
19516 if (side_effects.length > 0) {
19517 side_effects = make_node(AST_BlockStatement, node, {
19518 body: [ make_node(AST_SimpleStatement, node, {
19519 body: AST_Seq.from_array(side_effects)
19523 side_effects = null;
19525 if (def.length == 0 && !side_effects) {
19526 return make_node(AST_EmptyStatement, node);
19528 if (def.length == 0) {
19529 return side_effects;
19531 node.definitions = def;
19532 if (side_effects) {
19533 side_effects.body.unshift(node);
19534 node = side_effects;
19538 if (node instanceof AST_For && node.init instanceof AST_BlockStatement) {
19539 descend(node, this);
19540 var body = node.init.body.slice(0, -1);
19541 node.init = node.init.body.slice(-1)[0].body;
19543 return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
19547 if (node instanceof AST_Scope && node !== self) return node;
19549 self.transform(tt);
19552 AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
19553 var hoist_funs = compressor.option("hoist_funs");
19554 var hoist_vars = compressor.option("hoist_vars");
19556 if (hoist_funs || hoist_vars) {
19559 var vars = new Dictionary(), vars_found = 0, var_decl = 0;
19560 self.walk(new TreeWalker(function(node) {
19561 if (node instanceof AST_Scope && node !== self) return true;
19562 if (node instanceof AST_Var) {
19567 hoist_vars = hoist_vars && var_decl > 1;
19568 var tt = new TreeTransformer(function before(node) {
19569 if (node !== self) {
19570 if (node instanceof AST_Directive) {
19572 return make_node(AST_EmptyStatement, node);
19574 if (node instanceof AST_Defun && hoist_funs) {
19575 hoisted.push(node);
19576 return make_node(AST_EmptyStatement, node);
19578 if (node instanceof AST_Var && hoist_vars) {
19579 node.definitions.forEach(function(def) {
19580 vars.set(def.name.name, def);
19583 var seq = node.to_assignments();
19584 var p = tt.parent();
19585 if (p instanceof AST_ForIn && p.init === node) {
19586 if (seq == null) return node.definitions[0].name;
19589 if (p instanceof AST_For && p.init === node) {
19592 if (!seq) return make_node(AST_EmptyStatement, node);
19593 return make_node(AST_SimpleStatement, node, {
19597 if (node instanceof AST_Scope) return node;
19600 self = self.transform(tt);
19601 if (vars_found > 0) {
19603 vars.each(function(def, name) {
19604 if (self instanceof AST_Lambda && find_if(function(x) {
19605 return x.name == def.name.name;
19606 }, self.argnames)) {
19612 vars.set(name, def);
19615 if (defs.length > 0) {
19616 for (var i = 0; i < self.body.length; ) {
19617 if (self.body[i] instanceof AST_SimpleStatement) {
19618 var expr = self.body[i].body, sym, assign;
19619 if (expr instanceof AST_Assign && expr.operator == "=" && (sym = expr.left) instanceof AST_Symbol && vars.has(sym.name)) {
19620 var def = vars.get(sym.name);
19621 if (def.value) break;
19622 def.value = expr.right;
19625 self.body.splice(i, 1);
19628 if (expr instanceof AST_Seq && (assign = expr.car) instanceof AST_Assign && assign.operator == "=" && (sym = assign.left) instanceof AST_Symbol && vars.has(sym.name)) {
19629 var def = vars.get(sym.name);
19630 if (def.value) break;
19631 def.value = assign.right;
19634 self.body[i].body = expr.cdr;
19638 if (self.body[i] instanceof AST_EmptyStatement) {
19639 self.body.splice(i, 1);
19642 if (self.body[i] instanceof AST_BlockStatement) {
19643 var tmp = [ i, 1 ].concat(self.body[i].body);
19644 self.body.splice.apply(self.body, tmp);
19649 defs = make_node(AST_Var, self, {
19652 hoisted.push(defs);
19655 self.body = dirs.concat(hoisted, self.body);
19659 OPT(AST_SimpleStatement, function(self, compressor) {
19660 if (compressor.option("side_effects")) {
19661 if (!self.body.has_side_effects()) {
19662 compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
19663 return make_node(AST_EmptyStatement, self);
19668 OPT(AST_DWLoop, function(self, compressor) {
19669 var cond = self.condition.evaluate(compressor);
19670 self.condition = cond[0];
19671 if (!compressor.option("loops")) return self;
19672 if (cond.length > 1) {
19674 return make_node(AST_For, self, {
19677 } else if (self instanceof AST_While) {
19678 if (compressor.option("dead_code")) {
19680 extract_declarations_from_unreachable_code(compressor, self.body, a);
19681 return make_node(AST_BlockStatement, self, {
19689 function if_break_in_loop(self, compressor) {
19690 function drop_it(rest) {
19691 rest = as_statement_array(rest);
19692 if (self.body instanceof AST_BlockStatement) {
19693 self.body = self.body.clone();
19694 self.body.body = rest.concat(self.body.body.slice(1));
19695 self.body = self.body.transform(compressor);
19697 self.body = make_node(AST_BlockStatement, self.body, {
19699 }).transform(compressor);
19701 if_break_in_loop(self, compressor);
19703 var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
19704 if (first instanceof AST_If) {
19705 if (first.body instanceof AST_Break && compressor.loopcontrol_target(first.body.label) === self) {
19706 if (self.condition) {
19707 self.condition = make_node(AST_Binary, self.condition, {
19708 left: self.condition,
19710 right: first.condition.negate(compressor)
19713 self.condition = first.condition.negate(compressor);
19715 drop_it(first.alternative);
19716 } else if (first.alternative instanceof AST_Break && compressor.loopcontrol_target(first.alternative.label) === self) {
19717 if (self.condition) {
19718 self.condition = make_node(AST_Binary, self.condition, {
19719 left: self.condition,
19721 right: first.condition
19724 self.condition = first.condition;
19726 drop_it(first.body);
19730 OPT(AST_While, function(self, compressor) {
19731 if (!compressor.option("loops")) return self;
19732 self = AST_DWLoop.prototype.optimize.call(self, compressor);
19733 if (self instanceof AST_While) {
19734 if_break_in_loop(self, compressor);
19735 self = make_node(AST_For, self, self).transform(compressor);
19739 OPT(AST_For, function(self, compressor) {
19740 var cond = self.condition;
19742 cond = cond.evaluate(compressor);
19743 self.condition = cond[0];
19745 if (!compressor.option("loops")) return self;
19747 if (cond.length > 1 && !cond[1]) {
19748 if (compressor.option("dead_code")) {
19750 if (self.init instanceof AST_Statement) {
19752 } else if (self.init) {
19753 a.push(make_node(AST_SimpleStatement, self.init, {
19757 extract_declarations_from_unreachable_code(compressor, self.body, a);
19758 return make_node(AST_BlockStatement, self, {
19764 if_break_in_loop(self, compressor);
19767 OPT(AST_If, function(self, compressor) {
19768 if (!compressor.option("conditionals")) return self;
19769 var cond = self.condition.evaluate(compressor);
19770 self.condition = cond[0];
19771 if (cond.length > 1) {
19773 compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
19774 if (compressor.option("dead_code")) {
19776 if (self.alternative) {
19777 extract_declarations_from_unreachable_code(compressor, self.alternative, a);
19780 return make_node(AST_BlockStatement, self, {
19782 }).transform(compressor);
19785 compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
19786 if (compressor.option("dead_code")) {
19788 extract_declarations_from_unreachable_code(compressor, self.body, a);
19789 if (self.alternative) a.push(self.alternative);
19790 return make_node(AST_BlockStatement, self, {
19792 }).transform(compressor);
19796 if (is_empty(self.alternative)) self.alternative = null;
19797 var negated = self.condition.negate(compressor);
19798 var negated_is_best = best_of(self.condition, negated) === negated;
19799 if (self.alternative && negated_is_best) {
19800 negated_is_best = false;
19801 self.condition = negated;
19802 var tmp = self.body;
19803 self.body = self.alternative || make_node(AST_EmptyStatement);
19804 self.alternative = tmp;
19806 if (is_empty(self.body) && is_empty(self.alternative)) {
19807 return make_node(AST_SimpleStatement, self.condition, {
19808 body: self.condition
19809 }).transform(compressor);
19811 if (self.body instanceof AST_SimpleStatement && self.alternative instanceof AST_SimpleStatement) {
19812 return make_node(AST_SimpleStatement, self, {
19813 body: make_node(AST_Conditional, self, {
19814 condition: self.condition,
19815 consequent: self.body.body,
19816 alternative: self.alternative.body
19818 }).transform(compressor);
19820 if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
19821 if (negated_is_best) return make_node(AST_SimpleStatement, self, {
19822 body: make_node(AST_Binary, self, {
19825 right: self.body.body
19827 }).transform(compressor);
19828 return make_node(AST_SimpleStatement, self, {
19829 body: make_node(AST_Binary, self, {
19831 left: self.condition,
19832 right: self.body.body
19834 }).transform(compressor);
19836 if (self.body instanceof AST_EmptyStatement && self.alternative && self.alternative instanceof AST_SimpleStatement) {
19837 return make_node(AST_SimpleStatement, self, {
19838 body: make_node(AST_Binary, self, {
19840 left: self.condition,
19841 right: self.alternative.body
19843 }).transform(compressor);
19845 if (self.body instanceof AST_Exit && self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) {
19846 return make_node(self.body.CTOR, self, {
19847 value: make_node(AST_Conditional, self, {
19848 condition: self.condition,
19849 consequent: self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
19850 alternative: self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
19852 }).transform(compressor);
19854 if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) {
19855 self.condition = make_node(AST_Binary, self.condition, {
19857 left: self.condition,
19858 right: self.body.condition
19859 }).transform(compressor);
19860 self.body = self.body.body;
19862 if (aborts(self.body)) {
19863 if (self.alternative) {
19864 var alt = self.alternative;
19865 self.alternative = null;
19866 return make_node(AST_BlockStatement, self, {
19867 body: [ self, alt ]
19868 }).transform(compressor);
19871 if (aborts(self.alternative)) {
19872 var body = self.body;
19873 self.body = self.alternative;
19874 self.condition = negated_is_best ? negated : self.condition.negate(compressor);
19875 self.alternative = null;
19876 return make_node(AST_BlockStatement, self, {
19877 body: [ self, body ]
19878 }).transform(compressor);
19882 OPT(AST_Switch, function(self, compressor) {
19883 if (self.body.length == 0 && compressor.option("conditionals")) {
19884 return make_node(AST_SimpleStatement, self, {
19885 body: self.expression
19886 }).transform(compressor);
19889 var last_branch = self.body[self.body.length - 1];
19891 var stat = last_branch.body[last_branch.body.length - 1];
19892 if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self) last_branch.body.pop();
19893 if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
19900 var exp = self.expression.evaluate(compressor);
19901 out: if (exp.length == 2) try {
19902 self.expression = exp[0];
19903 if (!compressor.option("dead_code")) break out;
19904 var value = exp[1];
19906 var in_block = false;
19907 var started = false;
19908 var stopped = false;
19909 var ruined = false;
19910 var tt = new TreeTransformer(function(node, descend, in_list) {
19911 if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
19913 } else if (node instanceof AST_Switch && node === self) {
19914 node = node.clone();
19915 descend(node, this);
19916 return ruined ? node : make_node(AST_BlockStatement, node, {
19917 body: node.body.reduce(function(a, branch) {
19918 return a.concat(branch.body);
19920 }).transform(compressor);
19921 } else if (node instanceof AST_If || node instanceof AST_Try) {
19924 descend(node, this);
19927 } else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
19928 var save = in_block;
19930 descend(node, this);
19933 } else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
19938 if (in_block) return node;
19940 return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
19941 } else if (node instanceof AST_SwitchBranch && this.parent() === self) {
19942 if (stopped) return MAP.skip;
19943 if (node instanceof AST_Case) {
19944 var exp = node.expression.evaluate(compressor);
19945 if (exp.length < 2) {
19948 if (exp[1] === value || started) {
19950 if (aborts(node)) stopped = true;
19951 descend(node, this);
19956 descend(node, this);
19960 tt.stack = compressor.stack.slice();
19961 self = self.transform(tt);
19963 if (ex !== self) throw ex;
19967 OPT(AST_Case, function(self, compressor) {
19968 self.body = tighten_body(self.body, compressor);
19971 OPT(AST_Try, function(self, compressor) {
19972 self.body = tighten_body(self.body, compressor);
19975 AST_Definitions.DEFMETHOD("remove_initializers", function() {
19976 this.definitions.forEach(function(def) {
19980 AST_Definitions.DEFMETHOD("to_assignments", function() {
19981 var assignments = this.definitions.reduce(function(a, def) {
19983 var name = make_node(AST_SymbolRef, def.name, def.name);
19984 a.push(make_node(AST_Assign, def, {
19992 if (assignments.length == 0) return null;
19993 return AST_Seq.from_array(assignments);
19995 OPT(AST_Definitions, function(self, compressor) {
19996 if (self.definitions.length == 0) return make_node(AST_EmptyStatement, self);
19999 OPT(AST_Function, function(self, compressor) {
20000 self = AST_Lambda.prototype.optimize.call(self, compressor);
20001 if (compressor.option("unused")) {
20002 if (self.name && self.name.unreferenced()) {
20008 OPT(AST_Call, function(self, compressor) {
20009 if (compressor.option("unsafe")) {
20010 var exp = self.expression;
20011 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
20012 switch (exp.name) {
20014 if (self.args.length != 1) {
20015 return make_node(AST_Array, self, {
20016 elements: self.args
20022 if (self.args.length == 0) {
20023 return make_node(AST_Object, self, {
20030 if (self.args.length == 0) return make_node(AST_String, self, {
20033 return make_node(AST_Binary, self, {
20034 left: self.args[0],
20036 right: make_node(AST_String, self, {
20042 if (all(self.args, function(x) {
20043 return x instanceof AST_String;
20046 var code = "(function(" + self.args.slice(0, -1).map(function(arg) {
20048 }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
20049 var ast = parse(code);
20050 ast.figure_out_scope();
20051 var comp = new Compressor(compressor.options);
20052 ast = ast.transform(comp);
20053 ast.figure_out_scope();
20054 ast.mangle_names();
20055 var fun = ast.body[0].body.expression;
20056 var args = fun.argnames.map(function(arg, i) {
20057 return make_node(AST_String, self.args[i], {
20058 value: arg.print_to_string()
20061 var code = OutputStream();
20062 AST_BlockStatement.prototype._codegen.call(fun, fun, code);
20063 code = code.toString().replace(/^\{|\}$/g, "");
20064 args.push(make_node(AST_String, self.args[self.args.length - 1], {
20070 if (ex instanceof JS_Parse_Error) {
20071 compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
20072 compressor.warn(ex.toString());
20080 } else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
20081 return make_node(AST_Binary, self, {
20082 left: make_node(AST_String, self, {
20086 right: exp.expression
20087 }).transform(compressor);
20090 if (compressor.option("side_effects")) {
20091 if (self.expression instanceof AST_Function && self.args.length == 0 && !AST_Block.prototype.has_side_effects.call(self.expression)) {
20092 return make_node(AST_Undefined, self).transform(compressor);
20097 OPT(AST_New, function(self, compressor) {
20098 if (compressor.option("unsafe")) {
20099 var exp = self.expression;
20100 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
20101 switch (exp.name) {
20107 return make_node(AST_Call, self, self).transform(compressor);
20113 OPT(AST_Seq, function(self, compressor) {
20114 if (!compressor.option("side_effects")) return self;
20115 if (!self.car.has_side_effects()) {
20117 if (!(self.cdr instanceof AST_SymbolRef && self.cdr.name == "eval" && self.cdr.undeclared() && (p = compressor.parent()) instanceof AST_Call && p.expression === self)) {
20121 if (compressor.option("cascade")) {
20122 if (self.car instanceof AST_Assign && !self.car.left.has_side_effects() && self.car.left.equivalent_to(self.cdr)) {
20125 if (!self.car.has_side_effects() && !self.cdr.has_side_effects() && self.car.equivalent_to(self.cdr)) {
20131 AST_Unary.DEFMETHOD("lift_sequences", function(compressor) {
20132 if (compressor.option("sequences")) {
20133 if (this.expression instanceof AST_Seq) {
20134 var seq = this.expression;
20135 var x = seq.to_array();
20136 this.expression = x.pop();
20138 seq = AST_Seq.from_array(x).transform(compressor);
20144 OPT(AST_UnaryPostfix, function(self, compressor) {
20145 return self.lift_sequences(compressor);
20147 OPT(AST_UnaryPrefix, function(self, compressor) {
20148 self = self.lift_sequences(compressor);
20149 var e = self.expression;
20150 if (compressor.option("booleans") && compressor.in_boolean_context()) {
20151 switch (self.operator) {
20153 if (e instanceof AST_UnaryPrefix && e.operator == "!") {
20154 return e.expression;
20159 compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
20160 return make_node(AST_True, self);
20162 if (e instanceof AST_Binary && self.operator == "!") {
20163 self = best_of(self, e.negate(compressor));
20166 return self.evaluate(compressor)[0];
20168 AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
20169 if (compressor.option("sequences")) {
20170 if (this.left instanceof AST_Seq) {
20171 var seq = this.left;
20172 var x = seq.to_array();
20173 this.left = x.pop();
20175 seq = AST_Seq.from_array(x).transform(compressor);
20178 if (this.right instanceof AST_Seq && !(this.operator == "||" || this.operator == "&&") && !this.left.has_side_effects()) {
20179 var seq = this.right;
20180 var x = seq.to_array();
20181 this.right = x.pop();
20183 seq = AST_Seq.from_array(x).transform(compressor);
20189 var commutativeOperators = makePredicate("== === != !== * & | ^");
20190 OPT(AST_Binary, function(self, compressor) {
20191 function reverse(op, force) {
20192 if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) {
20193 if (op) self.operator = op;
20194 var tmp = self.left;
20195 self.left = self.right;
20199 if (commutativeOperators(self.operator)) {
20200 if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) {
20201 reverse(null, true);
20204 self = self.lift_sequences(compressor);
20205 if (compressor.option("comparisons")) switch (self.operator) {
20208 if (self.left.is_string(compressor) && self.right.is_string(compressor) || self.left.is_boolean() && self.right.is_boolean()) {
20209 self.operator = self.operator.substr(0, 2);
20214 if (self.left instanceof AST_String && self.left.value == "undefined" && self.right instanceof AST_UnaryPrefix && self.right.operator == "typeof" && compressor.option("unsafe")) {
20215 if (!(self.right.expression instanceof AST_SymbolRef) || !self.right.expression.undeclared()) {
20216 self.right = self.right.expression;
20217 self.left = make_node(AST_Undefined, self.left).optimize(compressor);
20218 if (self.operator.length == 2) self.operator += "=";
20223 if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
20225 var ll = self.left.evaluate(compressor);
20226 var rr = self.right.evaluate(compressor);
20227 if (ll.length > 1 && !ll[1] || rr.length > 1 && !rr[1]) {
20228 compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
20229 return make_node(AST_False, self);
20231 if (ll.length > 1 && ll[1]) {
20234 if (rr.length > 1 && rr[1]) {
20240 var ll = self.left.evaluate(compressor);
20241 var rr = self.right.evaluate(compressor);
20242 if (ll.length > 1 && ll[1] || rr.length > 1 && rr[1]) {
20243 compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
20244 return make_node(AST_True, self);
20246 if (ll.length > 1 && !ll[1]) {
20249 if (rr.length > 1 && !rr[1]) {
20255 var ll = self.left.evaluate(compressor);
20256 var rr = self.right.evaluate(compressor);
20257 if (ll.length > 1 && ll[0] instanceof AST_String && ll[1] || rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
20258 compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
20259 return make_node(AST_True, self);
20263 var exp = self.evaluate(compressor);
20264 if (exp.length > 1) {
20265 if (best_of(exp[0], self) !== self) return exp[0];
20267 if (compressor.option("comparisons")) {
20268 if (!(compressor.parent() instanceof AST_Binary) || compressor.parent() instanceof AST_Assign) {
20269 var negated = make_node(AST_UnaryPrefix, self, {
20271 expression: self.negate(compressor)
20273 self = best_of(self, negated);
20275 switch (self.operator) {
20285 if (self.operator == "+" && self.right instanceof AST_String && self.right.getValue() === "" && self.left instanceof AST_Binary && self.left.operator == "+" && self.left.is_string(compressor)) {
20290 OPT(AST_SymbolRef, function(self, compressor) {
20291 if (self.undeclared()) {
20292 var defines = compressor.option("global_defs");
20293 if (defines && defines.hasOwnProperty(self.name)) {
20294 return make_node_from_constant(compressor, defines[self.name], self);
20296 switch (self.name) {
20298 return make_node(AST_Undefined, self);
20301 return make_node(AST_NaN, self);
20304 return make_node(AST_Infinity, self);
20309 OPT(AST_Undefined, function(self, compressor) {
20310 if (compressor.option("unsafe")) {
20311 var scope = compressor.find_parent(AST_Scope);
20312 var undef = scope.find_variable("undefined");
20314 var ref = make_node(AST_SymbolRef, self, {
20325 var ASSIGN_OPS = [ "+", "-", "/", "*", "%", ">>", "<<", ">>>", "|", "^", "&" ];
20326 OPT(AST_Assign, function(self, compressor) {
20327 self = self.lift_sequences(compressor);
20328 if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary && self.right.left instanceof AST_SymbolRef && self.right.left.name == self.left.name && member(self.right.operator, ASSIGN_OPS)) {
20329 self.operator = self.right.operator + "=";
20330 self.right = self.right.right;
20334 OPT(AST_Conditional, function(self, compressor) {
20335 if (!compressor.option("conditionals")) return self;
20336 if (self.condition instanceof AST_Seq) {
20337 var car = self.condition.car;
20338 self.condition = self.condition.cdr;
20339 return AST_Seq.cons(car, self);
20341 var cond = self.condition.evaluate(compressor);
20342 if (cond.length > 1) {
20344 compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
20345 return self.consequent;
20347 compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
20348 return self.alternative;
20351 var negated = cond[0].negate(compressor);
20352 if (best_of(cond[0], negated) === negated) {
20353 self = make_node(AST_Conditional, self, {
20354 condition: negated,
20355 consequent: self.alternative,
20356 alternative: self.consequent
20359 var consequent = self.consequent;
20360 var alternative = self.alternative;
20361 if (consequent instanceof AST_Assign && alternative instanceof AST_Assign && consequent.operator == alternative.operator && consequent.left.equivalent_to(alternative.left)) {
20362 self = make_node(AST_Assign, self, {
20363 operator: consequent.operator,
20364 left: consequent.left,
20365 right: make_node(AST_Conditional, self, {
20366 condition: self.condition,
20367 consequent: consequent.right,
20368 alternative: alternative.right
20374 OPT(AST_Boolean, function(self, compressor) {
20375 if (compressor.option("booleans")) {
20376 var p = compressor.parent();
20377 if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) {
20378 compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
20379 operator: p.operator,
20381 file: p.start.file,
20382 line: p.start.line,
20385 return make_node(AST_Number, self, {
20389 return make_node(AST_UnaryPrefix, self, {
20391 expression: make_node(AST_Number, self, {
20392 value: 1 - self.value
20398 OPT(AST_Sub, function(self, compressor) {
20399 var prop = self.property;
20400 if (prop instanceof AST_String && compressor.option("properties")) {
20401 prop = prop.getValue();
20402 if (compressor.option("screw_ie8") && RESERVED_WORDS(prop) || !RESERVED_WORDS(prop) && is_identifier_string(prop)) {
20403 return make_node(AST_Dot, self, {
20404 expression: self.expression,
20411 function literals_in_boolean_context(self, compressor) {
20412 if (compressor.option("booleans") && compressor.in_boolean_context()) {
20413 return make_node(AST_True, self);
20417 OPT(AST_Array, literals_in_boolean_context);
20418 OPT(AST_Object, literals_in_boolean_context);
20419 OPT(AST_RegExp, literals_in_boolean_context);
20422 function SourceMap(options) {
20423 options = defaults(options, {
20428 var generator = new MOZ_SourceMap.SourceMapGenerator({
20429 file: options.file,
20430 sourceRoot: options.root
20432 var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
20433 function add(source, gen_line, gen_col, orig_line, orig_col, name) {
20435 var info = orig_map.originalPositionFor({
20439 source = info.source;
20440 orig_line = info.line;
20441 orig_col = info.column;
20444 generator.addMapping({
20462 toString: function() {
20463 return generator.toString();
20470 TryStatement: function(M) {
20471 return new AST_Try({
20472 start: my_start_token(M),
20473 end: my_end_token(M),
20474 body: from_moz(M.block).body,
20475 bcatch: from_moz(M.handlers[0]),
20476 bfinally: M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
20479 CatchClause: function(M) {
20480 return new AST_Catch({
20481 start: my_start_token(M),
20482 end: my_end_token(M),
20483 argname: from_moz(M.param),
20484 body: from_moz(M.body).body
20487 ObjectExpression: function(M) {
20488 return new AST_Object({
20489 start: my_start_token(M),
20490 end: my_end_token(M),
20491 properties: M.properties.map(function(prop) {
20492 var key = prop.key;
20493 var name = key.type == "Identifier" ? key.name : key.value;
20495 start: my_start_token(key),
20496 end: my_end_token(prop.value),
20498 value: from_moz(prop.value)
20500 switch (prop.kind) {
20502 return new AST_ObjectKeyVal(args);
20505 args.value.name = from_moz(key);
20506 return new AST_ObjectSetter(args);
20509 args.value.name = from_moz(key);
20510 return new AST_ObjectGetter(args);
20515 SequenceExpression: function(M) {
20516 return AST_Seq.from_array(M.expressions.map(from_moz));
20518 MemberExpression: function(M) {
20519 return new (M.computed ? AST_Sub : AST_Dot)({
20520 start: my_start_token(M),
20521 end: my_end_token(M),
20522 property: M.computed ? from_moz(M.property) : M.property.name,
20523 expression: from_moz(M.object)
20526 SwitchCase: function(M) {
20527 return new (M.test ? AST_Case : AST_Default)({
20528 start: my_start_token(M),
20529 end: my_end_token(M),
20530 expression: from_moz(M.test),
20531 body: M.consequent.map(from_moz)
20534 Literal: function(M) {
20535 var val = M.value, args = {
20536 start: my_start_token(M),
20537 end: my_end_token(M)
20539 if (val === null) return new AST_Null(args);
20540 switch (typeof val) {
20543 return new AST_String(args);
20547 return new AST_Number(args);
20550 return new (val ? AST_True : AST_False)(args);
20554 return new AST_RegExp(args);
20557 UnaryExpression: From_Moz_Unary,
20558 UpdateExpression: From_Moz_Unary,
20559 Identifier: function(M) {
20560 var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
20561 return new (M.name == "this" ? AST_This : p.type == "LabeledStatement" ? AST_Label : p.type == "VariableDeclarator" && p.id === M ? p.kind == "const" ? AST_SymbolConst : AST_SymbolVar : p.type == "FunctionExpression" ? p.id === M ? AST_SymbolLambda : AST_SymbolFunarg : p.type == "FunctionDeclaration" ? p.id === M ? AST_SymbolDefun : AST_SymbolFunarg : p.type == "CatchClause" ? AST_SymbolCatch : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef : AST_SymbolRef)({
20562 start: my_start_token(M),
20563 end: my_end_token(M),
20568 function From_Moz_Unary(M) {
20569 var prefix = "prefix" in M ? M.prefix : M.type == "UnaryExpression" ? true : false;
20570 return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
20571 start: my_start_token(M),
20572 end: my_end_token(M),
20573 operator: M.operator,
20574 expression: from_moz(M.argument)
20577 var ME_TO_MOZ = {};
20578 map("Node", AST_Node);
20579 map("Program", AST_Toplevel, "body@body");
20580 map("Function", AST_Function, "id>name, params@argnames, body%body");
20581 map("EmptyStatement", AST_EmptyStatement);
20582 map("BlockStatement", AST_BlockStatement, "body@body");
20583 map("ExpressionStatement", AST_SimpleStatement, "expression>body");
20584 map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
20585 map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
20586 map("BreakStatement", AST_Break, "label>label");
20587 map("ContinueStatement", AST_Continue, "label>label");
20588 map("WithStatement", AST_With, "object>expression, body>body");
20589 map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
20590 map("ReturnStatement", AST_Return, "argument>value");
20591 map("ThrowStatement", AST_Throw, "argument>value");
20592 map("WhileStatement", AST_While, "test>condition, body>body");
20593 map("DoWhileStatement", AST_Do, "test>condition, body>body");
20594 map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
20595 map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
20596 map("DebuggerStatement", AST_Debugger);
20597 map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
20598 map("VariableDeclaration", AST_Var, "declarations@definitions");
20599 map("VariableDeclarator", AST_VarDef, "id>name, init>value");
20600 map("ThisExpression", AST_This);
20601 map("ArrayExpression", AST_Array, "elements@elements");
20602 map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
20603 map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
20604 map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
20605 map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
20606 map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
20607 map("NewExpression", AST_New, "callee>expression, arguments@args");
20608 map("CallExpression", AST_Call, "callee>expression, arguments@args");
20609 function my_start_token(moznode) {
20610 return new AST_Token({
20611 file: moznode.loc && moznode.loc.source,
20612 line: moznode.loc && moznode.loc.start.line,
20613 col: moznode.loc && moznode.loc.start.column,
20614 pos: moznode.start,
20615 endpos: moznode.start
20618 function my_end_token(moznode) {
20619 return new AST_Token({
20620 file: moznode.loc && moznode.loc.source,
20621 line: moznode.loc && moznode.loc.end.line,
20622 col: moznode.loc && moznode.loc.end.column,
20624 endpos: moznode.end
20627 function map(moztype, mytype, propmap) {
20628 var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
20629 moz_to_me += "return new mytype({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)";
20630 if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
20631 var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
20632 if (!m) throw new Error("Can't understand property map: " + prop);
20633 var moz = "M." + m[1], how = m[2], my = m[3];
20634 moz_to_me += ",\n" + my + ": ";
20636 moz_to_me += moz + ".map(from_moz)";
20637 } else if (how == ">") {
20638 moz_to_me += "from_moz(" + moz + ")";
20639 } else if (how == "=") {
20641 } else if (how == "%") {
20642 moz_to_me += "from_moz(" + moz + ").body";
20643 } else throw new Error("Can't understand operator in propmap: " + prop);
20645 moz_to_me += "\n})}";
20646 moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(mytype, my_start_token, my_end_token, from_moz);
20647 return MOZ_TO_ME[moztype] = moz_to_me;
20649 var FROM_MOZ_STACK = null;
20650 function from_moz(node) {
20651 FROM_MOZ_STACK.push(node);
20652 var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
20653 FROM_MOZ_STACK.pop();
20656 AST_Node.from_mozilla_ast = function(node) {
20657 var save_stack = FROM_MOZ_STACK;
20658 FROM_MOZ_STACK = [];
20659 var ast = from_moz(node);
20660 FROM_MOZ_STACK = save_stack;
20664 exports["array_to_hash"] = array_to_hash;
20665 exports["slice"] = slice;
20666 exports["characters"] = characters;
20667 exports["member"] = member;
20668 exports["find_if"] = find_if;
20669 exports["repeat_string"] = repeat_string;
20670 exports["DefaultsError"] = DefaultsError;
20671 exports["defaults"] = defaults;
20672 exports["merge"] = merge;
20673 exports["noop"] = noop;
20674 exports["MAP"] = MAP;
20675 exports["push_uniq"] = push_uniq;
20676 exports["string_template"] = string_template;
20677 exports["remove"] = remove;
20678 exports["mergeSort"] = mergeSort;
20679 exports["set_difference"] = set_difference;
20680 exports["set_intersection"] = set_intersection;
20681 exports["makePredicate"] = makePredicate;
20682 exports["all"] = all;
20683 exports["Dictionary"] = Dictionary;
20684 exports["DEFNODE"] = DEFNODE;
20685 exports["AST_Token"] = AST_Token;
20686 exports["AST_Node"] = AST_Node;
20687 exports["AST_Statement"] = AST_Statement;
20688 exports["AST_Debugger"] = AST_Debugger;
20689 exports["AST_Directive"] = AST_Directive;
20690 exports["AST_SimpleStatement"] = AST_SimpleStatement;
20691 exports["walk_body"] = walk_body;
20692 exports["AST_Block"] = AST_Block;
20693 exports["AST_BlockStatement"] = AST_BlockStatement;
20694 exports["AST_EmptyStatement"] = AST_EmptyStatement;
20695 exports["AST_StatementWithBody"] = AST_StatementWithBody;
20696 exports["AST_LabeledStatement"] = AST_LabeledStatement;
20697 exports["AST_DWLoop"] = AST_DWLoop;
20698 exports["AST_Do"] = AST_Do;
20699 exports["AST_While"] = AST_While;
20700 exports["AST_For"] = AST_For;
20701 exports["AST_ForIn"] = AST_ForIn;
20702 exports["AST_With"] = AST_With;
20703 exports["AST_Scope"] = AST_Scope;
20704 exports["AST_Toplevel"] = AST_Toplevel;
20705 exports["AST_Lambda"] = AST_Lambda;
20706 exports["AST_Accessor"] = AST_Accessor;
20707 exports["AST_Function"] = AST_Function;
20708 exports["AST_Defun"] = AST_Defun;
20709 exports["AST_Jump"] = AST_Jump;
20710 exports["AST_Exit"] = AST_Exit;
20711 exports["AST_Return"] = AST_Return;
20712 exports["AST_Throw"] = AST_Throw;
20713 exports["AST_LoopControl"] = AST_LoopControl;
20714 exports["AST_Break"] = AST_Break;
20715 exports["AST_Continue"] = AST_Continue;
20716 exports["AST_If"] = AST_If;
20717 exports["AST_Switch"] = AST_Switch;
20718 exports["AST_SwitchBranch"] = AST_SwitchBranch;
20719 exports["AST_Default"] = AST_Default;
20720 exports["AST_Case"] = AST_Case;
20721 exports["AST_Try"] = AST_Try;
20722 exports["AST_Catch"] = AST_Catch;
20723 exports["AST_Finally"] = AST_Finally;
20724 exports["AST_Definitions"] = AST_Definitions;
20725 exports["AST_Var"] = AST_Var;
20726 exports["AST_Const"] = AST_Const;
20727 exports["AST_VarDef"] = AST_VarDef;
20728 exports["AST_Call"] = AST_Call;
20729 exports["AST_New"] = AST_New;
20730 exports["AST_Seq"] = AST_Seq;
20731 exports["AST_PropAccess"] = AST_PropAccess;
20732 exports["AST_Dot"] = AST_Dot;
20733 exports["AST_Sub"] = AST_Sub;
20734 exports["AST_Unary"] = AST_Unary;
20735 exports["AST_UnaryPrefix"] = AST_UnaryPrefix;
20736 exports["AST_UnaryPostfix"] = AST_UnaryPostfix;
20737 exports["AST_Binary"] = AST_Binary;
20738 exports["AST_Conditional"] = AST_Conditional;
20739 exports["AST_Assign"] = AST_Assign;
20740 exports["AST_Array"] = AST_Array;
20741 exports["AST_Object"] = AST_Object;
20742 exports["AST_ObjectProperty"] = AST_ObjectProperty;
20743 exports["AST_ObjectKeyVal"] = AST_ObjectKeyVal;
20744 exports["AST_ObjectSetter"] = AST_ObjectSetter;
20745 exports["AST_ObjectGetter"] = AST_ObjectGetter;
20746 exports["AST_Symbol"] = AST_Symbol;
20747 exports["AST_SymbolAccessor"] = AST_SymbolAccessor;
20748 exports["AST_SymbolDeclaration"] = AST_SymbolDeclaration;
20749 exports["AST_SymbolVar"] = AST_SymbolVar;
20750 exports["AST_SymbolConst"] = AST_SymbolConst;
20751 exports["AST_SymbolFunarg"] = AST_SymbolFunarg;
20752 exports["AST_SymbolDefun"] = AST_SymbolDefun;
20753 exports["AST_SymbolLambda"] = AST_SymbolLambda;
20754 exports["AST_SymbolCatch"] = AST_SymbolCatch;
20755 exports["AST_Label"] = AST_Label;
20756 exports["AST_SymbolRef"] = AST_SymbolRef;
20757 exports["AST_LabelRef"] = AST_LabelRef;
20758 exports["AST_This"] = AST_This;
20759 exports["AST_Constant"] = AST_Constant;
20760 exports["AST_String"] = AST_String;
20761 exports["AST_Number"] = AST_Number;
20762 exports["AST_RegExp"] = AST_RegExp;
20763 exports["AST_Atom"] = AST_Atom;
20764 exports["AST_Null"] = AST_Null;
20765 exports["AST_NaN"] = AST_NaN;
20766 exports["AST_Undefined"] = AST_Undefined;
20767 exports["AST_Hole"] = AST_Hole;
20768 exports["AST_Infinity"] = AST_Infinity;
20769 exports["AST_Boolean"] = AST_Boolean;
20770 exports["AST_False"] = AST_False;
20771 exports["AST_True"] = AST_True;
20772 exports["TreeWalker"] = TreeWalker;
20773 exports["KEYWORDS"] = KEYWORDS;
20774 exports["KEYWORDS_ATOM"] = KEYWORDS_ATOM;
20775 exports["RESERVED_WORDS"] = RESERVED_WORDS;
20776 exports["KEYWORDS_BEFORE_EXPRESSION"] = KEYWORDS_BEFORE_EXPRESSION;
20777 exports["OPERATOR_CHARS"] = OPERATOR_CHARS;
20778 exports["RE_HEX_NUMBER"] = RE_HEX_NUMBER;
20779 exports["RE_OCT_NUMBER"] = RE_OCT_NUMBER;
20780 exports["RE_DEC_NUMBER"] = RE_DEC_NUMBER;
20781 exports["OPERATORS"] = OPERATORS;
20782 exports["WHITESPACE_CHARS"] = WHITESPACE_CHARS;
20783 exports["PUNC_BEFORE_EXPRESSION"] = PUNC_BEFORE_EXPRESSION;
20784 exports["PUNC_CHARS"] = PUNC_CHARS;
20785 exports["REGEXP_MODIFIERS"] = REGEXP_MODIFIERS;
20786 exports["UNICODE"] = UNICODE;
20787 exports["is_letter"] = is_letter;
20788 exports["is_digit"] = is_digit;
20789 exports["is_alphanumeric_char"] = is_alphanumeric_char;
20790 exports["is_unicode_combining_mark"] = is_unicode_combining_mark;
20791 exports["is_unicode_connector_punctuation"] = is_unicode_connector_punctuation;
20792 exports["is_identifier"] = is_identifier;
20793 exports["is_identifier_start"] = is_identifier_start;
20794 exports["is_identifier_char"] = is_identifier_char;
20795 exports["is_identifier_string"] = is_identifier_string;
20796 exports["parse_js_number"] = parse_js_number;
20797 exports["JS_Parse_Error"] = JS_Parse_Error;
20798 exports["js_error"] = js_error;
20799 exports["is_token"] = is_token;
20800 exports["EX_EOF"] = EX_EOF;
20801 exports["tokenizer"] = tokenizer;
20802 exports["UNARY_PREFIX"] = UNARY_PREFIX;
20803 exports["UNARY_POSTFIX"] = UNARY_POSTFIX;
20804 exports["ASSIGNMENT"] = ASSIGNMENT;
20805 exports["PRECEDENCE"] = PRECEDENCE;
20806 exports["STATEMENTS_WITH_LABELS"] = STATEMENTS_WITH_LABELS;
20807 exports["ATOMIC_START_TOKEN"] = ATOMIC_START_TOKEN;
20808 exports["parse"] = parse;
20809 exports["TreeTransformer"] = TreeTransformer;
20810 exports["SymbolDef"] = SymbolDef;
20811 exports["base54"] = base54;
20812 exports["OutputStream"] = OutputStream;
20813 exports["Compressor"] = Compressor;
20814 exports["SourceMap"] = SourceMap;
20815 })({}, function() {
20819 var UglifyJS = exports.UglifyJS;
20821 UglifyJS.AST_Node.warn_function = function(txt) {
20822 logger.error("uglifyjs2 WARN: " + txt);
20825 //JRB: MODIFIED FROM UGLIFY SOURCE
20826 //to take a name for the file, and then set toplevel.filename to be that name.
20827 exports.minify = function(files, options, name) {
20828 options = UglifyJS.defaults(options, {
20829 outSourceMap : null,
20831 inSourceMap : null,
20832 fromString : false,
20838 if (typeof files == "string")
20842 var toplevel = null;
20843 files.forEach(function(file){
20844 var code = options.fromString
20846 : rjsFile.readFile(file, "utf8");
20847 toplevel = UglifyJS.parse(code, {
20848 filename: options.fromString ? name : file,
20854 if (options.compress) {
20855 var compress = { warnings: options.warnings };
20856 UglifyJS.merge(compress, options.compress);
20857 toplevel.figure_out_scope();
20858 var sq = UglifyJS.Compressor(compress);
20859 toplevel = toplevel.transform(sq);
20863 if (options.mangle) {
20864 toplevel.figure_out_scope();
20865 toplevel.compute_char_frequency();
20866 toplevel.mangle_names(options.mangle);
20872 if (options.inSourceMap) {
20873 inMap = rjsFile.readFile(options.inSourceMap, "utf8");
20875 if (options.outSourceMap) map = UglifyJS.SourceMap({
20876 file: options.outSourceMap,
20878 root: options.sourceRoot
20880 var output = { source_map: map };
20881 if (options.output) {
20882 UglifyJS.merge(output, options.output);
20884 var stream = UglifyJS.OutputStream(output);
20885 toplevel.print(stream);
20887 code : stream + "",
20892 // exports.describe_ast = function() {
20893 // function doitem(ctor) {
20895 // ctor.SUBCLASSES.forEach(function(ctor){
20896 // sub[ctor.TYPE] = doitem(ctor);
20899 // if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS;
20900 // if (ctor.SUBCLASSES.length > 0) ret.sub = sub;
20903 // return doitem(UglifyJS.AST_Node).sub;
20906 exports.describe_ast = function() {
20907 var out = UglifyJS.OutputStream({ beautify: true });
20908 function doitem(ctor) {
20909 out.print("AST_" + ctor.TYPE);
20910 var props = ctor.SELF_PROPS.filter(function(prop){
20911 return !/^\$/.test(prop);
20913 if (props.length > 0) {
20915 out.with_parens(function(){
20916 props.forEach(function(prop, i){
20917 if (i) out.space();
20922 if (ctor.documentation) {
20924 out.print_string(ctor.documentation);
20926 if (ctor.SUBCLASSES.length > 0) {
20928 out.with_block(function(){
20929 ctor.SUBCLASSES.forEach(function(ctor, i){
20937 doitem(UglifyJS.AST_Node);
20943 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
20944 * Available via the MIT or new BSD license.
20945 * see: http://github.com/jrburke/requirejs for details
20948 /*jslint plusplus: true */
20949 /*global define: false */
20951 define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) {
20954 function arrayToString(ary) {
20957 ary.forEach(function (item, i) {
20958 output += (i > 0 ? ',' : '') + '"' + lang.jsEscape(item) + '"';
20966 //This string is saved off because JSLint complains
20967 //about obj.arguments use, as 'reserved word'
20968 var argPropName = 'arguments';
20970 //From an esprima example for traversing its ast.
20971 function traverse(object, visitor) {
20978 if (visitor.call(null, object) === false) {
20981 for (key in object) {
20982 if (object.hasOwnProperty(key)) {
20983 child = object[key];
20984 if (typeof child === 'object' && child !== null) {
20985 if (traverse(child, visitor) === false) {
20993 //Like traverse, but visitor returning false just
20994 //stops that subtree analysis, not the rest of tree
20996 function traverseBroad(object, visitor) {
21003 if (visitor.call(null, object) === false) {
21006 for (key in object) {
21007 if (object.hasOwnProperty(key)) {
21008 child = object[key];
21009 if (typeof child === 'object' && child !== null) {
21010 traverse(child, visitor);
21017 * Pulls out dependencies from an array literal with just string members.
21018 * If string literals, will just return those string values in an array,
21019 * skipping other items in the array.
21021 * @param {Node} node an AST node.
21023 * @returns {Array} an array of strings.
21024 * If null is returned, then it means the input node was not a valid
21027 function getValidDeps(node) {
21028 if (!node || node.type !== 'ArrayExpression' || !node.elements) {
21034 node.elements.some(function (elem) {
21035 if (elem.type === 'Literal') {
21036 deps.push(elem.value);
21040 return deps.length ? deps : undefined;
21044 * Main parse function. Returns a string of any valid require or
21045 * define/require.def calls as part of one JavaScript source string.
21046 * @param {String} moduleName the module name that represents this file.
21047 * It is used to create a default define if there is not one already for the
21048 * file. This allows properly tracing dependencies for builds. Otherwise, if
21049 * the file just has a require() call, the file dependencies will not be
21050 * properly reflected: the file will come before its dependencies.
21051 * @param {String} moduleName
21052 * @param {String} fileName
21053 * @param {String} fileContents
21054 * @param {Object} options optional options. insertNeedsDefine: true will
21055 * add calls to require.needsDefine() if appropriate.
21056 * @returns {String} JS source string or null, if no require or
21057 * define/require.def calls are found.
21059 function parse(moduleName, fileName, fileContents, options) {
21060 options = options || {};
21062 //Set up source input
21063 var i, moduleCall, depString,
21067 needsDefine = true,
21068 astRoot = esprima.parse(fileContents);
21070 parse.recurse(astRoot, function (callName, config, name, deps) {
21075 if (callName === 'define' && (!name || name === moduleName)) {
21076 needsDefine = false;
21080 //If there is no module name, the dependencies are for
21081 //this file/default module name.
21082 moduleDeps = moduleDeps.concat(deps);
21090 //If define was found, no need to dive deeper, unless
21091 //the config explicitly wants to dig deeper.
21092 return !!options.findNestedDependencies;
21095 if (options.insertNeedsDefine && needsDefine) {
21096 result += 'require.needsDefine("' + moduleName + '");';
21099 if (moduleDeps.length || moduleList.length) {
21100 for (i = 0; i < moduleList.length; i++) {
21101 moduleCall = moduleList[i];
21106 //If this is the main module for this file, combine any
21107 //"anonymous" dependencies (could come from a nested require
21108 //call) with this module.
21109 if (moduleCall.name === moduleName) {
21110 moduleCall.deps = moduleCall.deps.concat(moduleDeps);
21114 depString = arrayToString(moduleCall.deps);
21115 result += 'define("' + moduleCall.name + '",' +
21118 if (moduleDeps.length) {
21122 depString = arrayToString(moduleDeps);
21123 result += 'define("' + moduleName + '",' + depString + ');';
21127 return result || null;
21130 parse.traverse = traverse;
21131 parse.traverseBroad = traverseBroad;
21134 * Handles parsing a file recursively for require calls.
21135 * @param {Array} parentNode the AST node to start with.
21136 * @param {Function} onMatch function to call on a parse match.
21137 * @param {Object} [options] This is normally the build config options if
21140 parse.recurse = function (object, onMatch, options) {
21141 //Like traverse, but skips if branches that would not be processed
21142 //after has application that results in tests of true or false boolean
21145 hasHas = options && options.has;
21151 //If has replacement has resulted in if(true){} or if(false){}, take
21152 //the appropriate branch and skip the other one.
21153 if (hasHas && object.type === 'IfStatement' && object.test.type &&
21154 object.test.type === 'Literal') {
21155 if (object.test.value) {
21156 //Take the if branch
21157 this.recurse(object.consequent, onMatch, options);
21159 //Take the else branch
21160 this.recurse(object.alternate, onMatch, options);
21163 if (this.parseNode(object, onMatch) === false) {
21166 for (key in object) {
21167 if (object.hasOwnProperty(key)) {
21168 child = object[key];
21169 if (typeof child === 'object' && child !== null) {
21170 this.recurse(child, onMatch, options);
21178 * Determines if the file defines the require/define module API.
21179 * Specifically, it looks for the `define.amd = ` expression.
21180 * @param {String} fileName
21181 * @param {String} fileContents
21182 * @returns {Boolean}
21184 parse.definesRequire = function (fileName, fileContents) {
21187 traverse(esprima.parse(fileContents), function (node) {
21188 if (parse.hasDefineAmd(node)) {
21200 * Finds require("") calls inside a CommonJS anonymous module wrapped in a
21201 * define(function(require, exports, module){}) wrapper. These dependencies
21202 * will be added to a modified define() call that lists the dependencies
21203 * on the outside of the function.
21204 * @param {String} fileName
21205 * @param {String|Object} fileContents: a string of contents, or an already
21207 * @returns {Array} an array of module names that are dependencies. Always
21208 * returns an array, but could be of length zero.
21210 parse.getAnonDeps = function (fileName, fileContents) {
21211 var astRoot = typeof fileContents === 'string' ?
21212 esprima.parse(fileContents) : fileContents,
21213 defFunc = this.findAnonDefineFactory(astRoot);
21215 return parse.getAnonDepsFromNode(defFunc);
21219 * Finds require("") calls inside a CommonJS anonymous module wrapped
21220 * in a define function, given an AST node for the definition function.
21221 * @param {Node} node the AST node for the definition function.
21222 * @returns {Array} and array of dependency names. Can be of zero length.
21224 parse.getAnonDepsFromNode = function (node) {
21229 this.findRequireDepNames(node, deps);
21231 //If no deps, still add the standard CommonJS require, exports,
21232 //module, in that order, to the deps, but only if specified as
21233 //function args. In particular, if exports is used, it is favored
21234 //over the return value of the function, so only add it if asked.
21235 funcArgLength = node.params && node.params.length;
21236 if (funcArgLength) {
21237 deps = (funcArgLength > 1 ? ["require", "exports", "module"] :
21238 ["require"]).concat(deps);
21244 parse.isDefineNodeWithArgs = function (node) {
21245 return node && node.type === 'CallExpression' &&
21246 node.callee && node.callee.type === 'Identifier' &&
21247 node.callee.name === 'define' && node[argPropName];
21251 * Finds the function in define(function (require, exports, module){});
21252 * @param {Array} node
21253 * @returns {Boolean}
21255 parse.findAnonDefineFactory = function (node) {
21258 traverse(node, function (node) {
21261 if (parse.isDefineNodeWithArgs(node)) {
21263 //Just the factory function passed to define
21264 arg0 = node[argPropName][0];
21265 if (arg0 && arg0.type === 'FunctionExpression') {
21270 //A string literal module ID followed by the factory function.
21271 arg1 = node[argPropName][1];
21272 if (arg0.type === 'Literal' &&
21273 arg1 && arg1.type === 'FunctionExpression') {
21284 * Finds any config that is passed to requirejs. That includes calls to
21285 * require/requirejs.config(), as well as require({}, ...) and
21286 * requirejs({}, ...)
21287 * @param {String} fileContents
21289 * @returns {Object} a config details object with the following properties:
21290 * - config: {Object} the config object found. Can be undefined if no
21292 * - range: {Array} the start index and end index in the contents where
21293 * the config was found. Can be undefined if no config found.
21294 * Can throw an error if the config in the file cannot be evaluated in
21295 * a build context to valid JavaScript.
21297 parse.findConfig = function (fileContents) {
21298 /*jslint evil: true */
21299 var jsConfig, foundConfig, stringData, foundRange, quote, quoteMatch,
21300 quoteRegExp = /(:\s|\[\s*)(['"])/,
21301 astRoot = esprima.parse(fileContents, {
21305 traverse(astRoot, function (node) {
21307 requireType = parse.hasRequire(node);
21309 if (requireType && (requireType === 'require' ||
21310 requireType === 'requirejs' ||
21311 requireType === 'requireConfig' ||
21312 requireType === 'requirejsConfig')) {
21314 arg = node[argPropName] && node[argPropName][0];
21316 if (arg && arg.type === 'ObjectExpression') {
21317 stringData = parse.nodeToString(fileContents, arg);
21318 jsConfig = stringData.value;
21319 foundRange = stringData.range;
21323 arg = parse.getRequireObjectLiteral(node);
21325 stringData = parse.nodeToString(fileContents, arg);
21326 jsConfig = stringData.value;
21327 foundRange = stringData.range;
21335 quoteMatch = quoteRegExp.exec(jsConfig);
21336 quote = (quoteMatch && quoteMatch[2]) || '"';
21337 foundConfig = eval('(' + jsConfig + ')');
21341 config: foundConfig,
21347 /** Returns the node for the object literal assigned to require/requirejs,
21348 * for holding a declarative config.
21350 parse.getRequireObjectLiteral = function (node) {
21351 if (node.id && node.id.type === 'Identifier' &&
21352 (node.id.name === 'require' || node.id.name === 'requirejs') &&
21353 node.init && node.init.type === 'ObjectExpression') {
21359 * Renames require/requirejs/define calls to be ns + '.' + require/requirejs/define
21360 * Does *not* do .config calls though. See pragma.namespace for the complete
21361 * set of namespace transforms. This function is used because require calls
21362 * inside a define() call should not be renamed, so a simple regexp is not
21364 * @param {String} fileContents the contents to transform.
21365 * @param {String} ns the namespace, *not* including trailing dot.
21366 * @return {String} the fileContents with the namespace applied
21368 parse.renameNamespace = function (fileContents, ns) {
21371 astRoot = esprima.parse(fileContents, {
21375 parse.recurse(astRoot, function (callName, config, name, deps, node) {
21376 locs.push(node.loc);
21377 //Do not recurse into define functions, they should be using
21379 return callName !== 'define';
21383 lines = fileContents.split('\n');
21385 //Go backwards through the found locs, adding in the namespace name
21388 locs.forEach(function (loc) {
21389 var startIndex = loc.start.column,
21390 //start.line is 1-based, not 0 based.
21391 lineIndex = loc.start.line - 1,
21392 line = lines[lineIndex];
21394 lines[lineIndex] = line.substring(0, startIndex) +
21396 line.substring(startIndex,
21400 fileContents = lines.join('\n');
21403 return fileContents;
21407 * Finds all dependencies specified in dependency arrays and inside
21408 * simplified commonjs wrappers.
21409 * @param {String} fileName
21410 * @param {String} fileContents
21412 * @returns {Array} an array of dependency strings. The dependencies
21413 * have not been normalized, they may be relative IDs.
21415 parse.findDependencies = function (fileName, fileContents, options) {
21416 var dependencies = [],
21417 astRoot = esprima.parse(fileContents);
21419 parse.recurse(astRoot, function (callName, config, name, deps) {
21421 dependencies = dependencies.concat(deps);
21425 return dependencies;
21429 * Finds only CJS dependencies, ones that are the form
21430 * require('stringLiteral')
21432 parse.findCjsDependencies = function (fileName, fileContents) {
21433 var dependencies = [];
21435 traverse(esprima.parse(fileContents), function (node) {
21438 if (node && node.type === 'CallExpression' && node.callee &&
21439 node.callee.type === 'Identifier' &&
21440 node.callee.name === 'require' && node[argPropName] &&
21441 node[argPropName].length === 1) {
21442 arg = node[argPropName][0];
21443 if (arg.type === 'Literal') {
21444 dependencies.push(arg.value);
21449 return dependencies;
21452 //function define() {}
21453 parse.hasDefDefine = function (node) {
21454 return node.type === 'FunctionDeclaration' && node.id &&
21455 node.id.type === 'Identifier' && node.id.name === 'define';
21459 parse.hasDefineAmd = function (node) {
21460 return node && node.type === 'AssignmentExpression' &&
21461 node.left && node.left.type === 'MemberExpression' &&
21462 node.left.object && node.left.object.name === 'define' &&
21463 node.left.property && node.left.property.name === 'amd';
21466 //define.amd reference, as in: if (define.amd)
21467 parse.refsDefineAmd = function (node) {
21468 return node && node.type === 'MemberExpression' &&
21469 node.object && node.object.name === 'define' &&
21470 node.object.type === 'Identifier' &&
21471 node.property && node.property.name === 'amd' &&
21472 node.property.type === 'Identifier';
21475 //require(), requirejs(), require.config() and requirejs.config()
21476 parse.hasRequire = function (node) {
21478 c = node && node.callee;
21480 if (node && node.type === 'CallExpression' && c) {
21481 if (c.type === 'Identifier' &&
21482 (c.name === 'require' ||
21483 c.name === 'requirejs')) {
21484 //A require/requirejs({}, ...) call
21486 } else if (c.type === 'MemberExpression' &&
21488 c.object.type === 'Identifier' &&
21489 (c.object.name === 'require' ||
21490 c.object.name === 'requirejs') &&
21491 c.property && c.property.name === 'config') {
21492 // require/requirejs.config({}) call
21493 callName = c.object.name + 'Config';
21501 parse.hasDefine = function (node) {
21502 return node && node.type === 'CallExpression' && node.callee &&
21503 node.callee.type === 'Identifier' &&
21504 node.callee.name === 'define';
21508 * If there is a named define in the file, returns the name. Does not
21509 * scan for mulitple names, just the first one.
21511 parse.getNamedDefine = function (fileContents) {
21513 traverse(esprima.parse(fileContents), function (node) {
21514 if (node && node.type === 'CallExpression' && node.callee &&
21515 node.callee.type === 'Identifier' &&
21516 node.callee.name === 'define' &&
21517 node[argPropName] && node[argPropName][0] &&
21518 node[argPropName][0].type === 'Literal') {
21519 name = node[argPropName][0].value;
21528 * Determines if define(), require({}|[]) or requirejs was called in the
21529 * file. Also finds out if define() is declared and if define.amd is called.
21531 parse.usesAmdOrRequireJs = function (fileName, fileContents) {
21534 traverse(esprima.parse(fileContents), function (node) {
21535 var type, callName, arg;
21537 if (parse.hasDefDefine(node)) {
21538 //function define() {}
21539 type = 'declaresDefine';
21540 } else if (parse.hasDefineAmd(node)) {
21541 type = 'defineAmd';
21543 callName = parse.hasRequire(node);
21545 arg = node[argPropName] && node[argPropName][0];
21546 if (arg && (arg.type === 'ObjectExpression' ||
21547 arg.type === 'ArrayExpression')) {
21550 } else if (parse.hasDefine(node)) {
21567 * Determines if require(''), exports.x =, module.exports =,
21568 * __dirname, __filename are used. So, not strictly traditional CommonJS,
21569 * also checks for Node variants.
21571 parse.usesCommonJs = function (fileName, fileContents) {
21573 assignsExports = false;
21576 traverse(esprima.parse(fileContents), function (node) {
21578 exp = node.expression || node.init;
21580 if (node.type === 'Identifier' &&
21581 (node.name === '__dirname' || node.name === '__filename')) {
21582 type = node.name.substring(2);
21583 } else if (node.type === 'VariableDeclarator' && node.id &&
21584 node.id.type === 'Identifier' &&
21585 node.id.name === 'exports') {
21586 //Hmm, a variable assignment for exports, so does not use cjs
21588 type = 'varExports';
21589 } else if (exp && exp.type === 'AssignmentExpression' && exp.left &&
21590 exp.left.type === 'MemberExpression' && exp.left.object) {
21591 if (exp.left.object.name === 'module' && exp.left.property &&
21592 exp.left.property.name === 'exports') {
21593 type = 'moduleExports';
21594 } else if (exp.left.object.name === 'exports' &&
21595 exp.left.property) {
21599 } else if (node && node.type === 'CallExpression' && node.callee &&
21600 node.callee.type === 'Identifier' &&
21601 node.callee.name === 'require' && node[argPropName] &&
21602 node[argPropName].length === 1 &&
21603 node[argPropName][0].type === 'Literal') {
21608 if (type === 'varExports') {
21609 assignsExports = true;
21610 } else if (type !== 'exports' || !assignsExports) {
21623 parse.findRequireDepNames = function (node, deps) {
21624 traverse(node, function (node) {
21627 if (node && node.type === 'CallExpression' && node.callee &&
21628 node.callee.type === 'Identifier' &&
21629 node.callee.name === 'require' &&
21630 node[argPropName] && node[argPropName].length === 1) {
21632 arg = node[argPropName][0];
21633 if (arg.type === 'Literal') {
21634 deps.push(arg.value);
21641 * Determines if a specific node is a valid require or define/require.def
21643 * @param {Array} node
21644 * @param {Function} onMatch a function to call when a match is found.
21645 * It is passed the match name, and the config, name, deps possible args.
21646 * The config, name and deps args are not normalized.
21648 * @returns {String} a JS source string with the valid require/define call.
21651 parse.parseNode = function (node, onMatch) {
21652 var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode,
21653 args = node && node[argPropName],
21654 callName = parse.hasRequire(node);
21656 if (callName === 'require' || callName === 'requirejs') {
21657 //A plain require/requirejs call
21658 arg = node[argPropName] && node[argPropName][0];
21659 if (arg.type !== 'ArrayExpression') {
21660 if (arg.type === 'ObjectExpression') {
21661 //A config call, try the second arg.
21662 arg = node[argPropName][1];
21666 deps = getValidDeps(arg);
21671 return onMatch("require", null, null, deps, node);
21672 } else if (parse.hasDefine(node) && args && args.length) {
21677 if (name.type === 'ArrayExpression') {
21678 //No name, adjust args
21682 } else if (name.type === 'FunctionExpression') {
21683 //Just the factory, no name or deps
21685 name = deps = null;
21686 } else if (name.type !== 'Literal') {
21687 //An object literal, just null out
21688 name = deps = factory = null;
21691 if (name && name.type === 'Literal' && deps) {
21692 if (deps.type === 'FunctionExpression') {
21693 //deps is the factory
21696 } else if (deps.type === 'ObjectExpression') {
21697 //deps is object literal, null out
21698 deps = factory = null;
21699 } else if (deps.type === 'Identifier' && args.length === 2) {
21700 // define('id', factory)
21701 deps = factory = null;
21705 if (deps && deps.type === 'ArrayExpression') {
21706 deps = getValidDeps(deps);
21707 } else if (factory && factory.type === 'FunctionExpression') {
21708 //If no deps and a factory function, could be a commonjs sugar
21709 //wrapper, scan the function for dependencies.
21710 cjsDeps = parse.getAnonDepsFromNode(factory);
21711 if (cjsDeps.length) {
21714 } else if (deps || factory) {
21715 //Does not match the shape of an AMD call.
21719 //Just save off the name as a string instead of an AST object.
21720 if (name && name.type === 'Literal') {
21724 return onMatch("define", null, name, deps, node);
21725 } else if (node.type === 'CallExpression' && node.callee &&
21726 node.callee.type === 'FunctionExpression' &&
21727 node.callee.body && node.callee.body.body &&
21728 node.callee.body.body.length === 1 &&
21729 node.callee.body.body[0].type === 'IfStatement') {
21730 bodyNode = node.callee.body.body[0];
21731 //Look for a define(Identifier) case, but only if inside an
21732 //if that has a define.amd test
21733 if (bodyNode.consequent && bodyNode.consequent.body) {
21734 exp = bodyNode.consequent.body[0];
21735 if (exp.type === 'ExpressionStatement' && exp.expression &&
21736 parse.hasDefine(exp.expression) &&
21737 exp.expression.arguments &&
21738 exp.expression.arguments.length === 1 &&
21739 exp.expression.arguments[0].type === 'Identifier') {
21741 //Calls define(Identifier) as first statement in body.
21742 //Confirm the if test references define.amd
21743 traverse(bodyNode.test, function (node) {
21744 if (parse.refsDefineAmd(node)) {
21751 return onMatch("define", null, null, null, exp.expression);
21759 * Converts an AST node into a JS source string by extracting
21760 * the node's location from the given contents string. Assumes
21761 * esprima.parse() with loc was done.
21762 * @param {String} contents
21763 * @param {Object} node
21764 * @returns {String} a JS source string.
21766 parse.nodeToString = function (contents, node) {
21767 var loc = node.loc,
21768 lines = contents.split('\n'),
21769 firstLine = loc.start.line > 1 ?
21770 lines.slice(0, loc.start.line - 1).join('\n') + '\n' :
21772 preamble = firstLine +
21773 lines[loc.start.line - 1].substring(0, loc.start.column),
21774 extracted = lines[loc.start.line - 1].substring(loc.start.column) +
21776 lines.slice(loc.start.line, loc.end.line - 1).join('\n') +
21778 lines[loc.end.line - 1].substring(0, loc.end.column);
21784 preamble.length + extracted.length
21790 * Extracts license comments from JS text.
21791 * @param {String} fileName
21792 * @param {String} contents
21793 * @returns {String} a string of license comments.
21795 parse.getLicenseComments = function (fileName, contents) {
21796 var commentNode, refNode, subNode, value, i, j,
21797 //xpconnect's Reflect does not support comment or range, but
21798 //prefer continued operation vs strict parity of operation,
21799 //as license comments can be expressed in other ways, like
21800 //via wrap args, or linked via sourcemaps.
21801 ast = esprima.parse(contents, {
21807 lineEnd = contents.indexOf('\r') === -1 ? '\n' : '\r\n';
21809 if (ast.comments) {
21810 for (i = 0; i < ast.comments.length; i++) {
21811 commentNode = ast.comments[i];
21813 if (commentNode.type === 'Line') {
21814 value = '//' + commentNode.value + lineEnd;
21815 refNode = commentNode;
21817 if (i + 1 >= ast.comments.length) {
21820 //Look for immediately adjacent single line comments
21821 //since it could from a multiple line comment made out
21822 //of single line comments. Like this comment.
21823 for (j = i + 1; j < ast.comments.length; j++) {
21824 subNode = ast.comments[j];
21825 if (subNode.type === 'Line' &&
21826 subNode.range[0] === refNode.range[1] + 1) {
21827 //Adjacent single line comment. Collect it.
21828 value += '//' + subNode.value + lineEnd;
21831 //No more single line comment blocks. Break out
21832 //and continue outer looping.
21840 value = '/*' + commentNode.value + '*/' + lineEnd + lineEnd;
21843 if (!existsMap[value] && (value.indexOf('license') !== -1 ||
21844 (commentNode.type === 'Block' &&
21845 value.indexOf('/*!') === 0) ||
21846 value.indexOf('opyright') !== -1 ||
21847 value.indexOf('(c)') !== -1)) {
21850 existsMap[value] = true;
21862 * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
21863 * Available via the MIT or new BSD license.
21864 * see: http://github.com/jrburke/requirejs for details
21869 define('transform', [ './esprimaAdapter', './parse', 'logger', 'lang'],
21870 function (esprima, parse, logger, lang) {
21873 baseIndentRegExp = /^([ \t]+)/,
21874 indentRegExp = /\{[\r\n]+([ \t]+)/,
21875 keyRegExp = /^[_A-Za-z]([A-Za-z\d_]*)$/,
21876 bulkIndentRegExps = {
21881 function applyIndent(str, indent, lineReturn) {
21882 var regExp = bulkIndentRegExps[lineReturn];
21883 return str.replace(regExp, '$&' + indent);
21887 toTransport: function (namespace, moduleName, path, contents, onFound, options) {
21888 options = options || {};
21890 var astRoot, contentLines, modLine,
21897 astRoot = esprima.parse(contents, {
21901 logger.trace('toTransport skipping ' + path + ': ' +
21906 //Find the define calls and their position in the files.
21907 parse.traverseBroad(astRoot, function (node) {
21908 var args, firstArg, firstArgLoc, factoryNode,
21909 needsId, depAction, foundId,
21910 sourceUrlData, range,
21911 namespaceExists = false;
21913 namespaceExists = namespace &&
21914 node.type === 'CallExpression' &&
21915 node.callee && node.callee.object &&
21916 node.callee.object.type === 'Identifier' &&
21917 node.callee.object.name === namespace &&
21918 node.callee.property.type === 'Identifier' &&
21919 node.callee.property.name === 'define';
21921 if (namespaceExists || parse.isDefineNodeWithArgs(node)) {
21922 //The arguments are where its at.
21923 args = node.arguments;
21924 if (!args || !args.length) {
21928 firstArg = args[0];
21929 firstArgLoc = firstArg.loc;
21931 if (args.length === 1) {
21932 if (firstArg.type === 'Identifier') {
21933 //The define(factory) case, but
21934 //only allow it if one Identifier arg,
21935 //to limit impact of false positives.
21937 depAction = 'empty';
21938 } else if (firstArg.type === 'FunctionExpression') {
21939 //define(function(){})
21940 factoryNode = firstArg;
21942 depAction = 'scan';
21943 } else if (firstArg.type === 'ObjectExpression') {
21946 depAction = 'skip';
21947 } else if (firstArg.type === 'Literal' &&
21948 typeof firstArg.value === 'number') {
21951 depAction = 'skip';
21952 } else if (firstArg.type === 'UnaryExpression' &&
21953 firstArg.operator === '-' &&
21954 firstArg.argument &&
21955 firstArg.argument.type === 'Literal' &&
21956 typeof firstArg.argument.value === 'number') {
21957 //define('-12345');
21959 depAction = 'skip';
21960 } else if (firstArg.type === 'MemberExpression' &&
21962 firstArg.property &&
21963 firstArg.property.type === 'Identifier') {
21964 //define(this.key);
21966 depAction = 'empty';
21968 } else if (firstArg.type === 'ArrayExpression') {
21971 depAction = 'skip';
21972 } else if (firstArg.type === 'Literal' &&
21973 typeof firstArg.value === 'string') {
21974 //define('string', ....)
21975 //Already has an ID.
21977 if (args.length === 2 &&
21978 args[1].type === 'FunctionExpression') {
21979 //Needs dependency scanning.
21980 factoryNode = args[1];
21981 depAction = 'scan';
21983 depAction = 'skip';
21986 //Unknown define entity, keep looking, even
21987 //in the subtree for this node.
21994 depAction: depAction,
21995 namespaceExists: namespaceExists,
21997 defineLoc: node.loc,
21998 firstArgLoc: firstArgLoc,
21999 factoryNode: factoryNode,
22000 sourceUrlData: sourceUrlData
22003 //Only transform ones that do not have IDs. If it has an
22004 //ID but no dependency array, assume it is something like
22005 //a phonegap implementation, that has its own internal
22006 //define that cannot handle dependency array constructs,
22007 //and if it is a named module, then it means it has been
22008 //set for transport form.
22009 if (range.needsId) {
22011 logger.trace(path + ' has more than one anonymous ' +
22012 'define. May be a built file from another ' +
22013 'build system like, Ender. Skipping normalization.');
22018 defineInfos.push(range);
22020 } else if (depAction === 'scan') {
22022 if (scanCount > 1) {
22023 //Just go back to an array that just has the
22024 //anon one, since this is an already optimized
22025 //file like the phonegap one.
22027 defineInfos = foundAnon ? [foundAnon] : [];
22031 defineInfos.push(range);
22037 if (!defineInfos.length) {
22041 //Reverse the matches, need to start from the bottom of
22042 //the file to modify it, so that the ranges are still true
22044 defineInfos.reverse();
22046 contentLines = contents.split('\n');
22048 modLine = function (loc, contentInsertion) {
22049 var startIndex = loc.start.column,
22050 //start.line is 1-based, not 0 based.
22051 lineIndex = loc.start.line - 1,
22052 line = contentLines[lineIndex];
22053 contentLines[lineIndex] = line.substring(0, startIndex) +
22055 line.substring(startIndex,
22059 defineInfos.forEach(function (info) {
22061 contentInsertion = '',
22064 //Do the modifications "backwards", in other words, start with the
22065 //one that is farthest down and work up, so that the ranges in the
22066 //defineInfos still apply. So that means deps, id, then namespace.
22067 if (info.needsId && moduleName) {
22068 contentInsertion += "'" + moduleName + "',";
22071 if (info.depAction === 'scan') {
22072 deps = parse.getAnonDepsFromNode(info.factoryNode);
22075 depString = '[' + deps.map(function (dep) {
22076 return "'" + dep + "'";
22083 if (info.factoryNode) {
22084 //Already have a named module, need to insert the
22085 //dependencies after the name.
22086 modLine(info.factoryNode.loc, depString);
22088 contentInsertion += depString;
22092 if (contentInsertion) {
22093 modLine(info.firstArgLoc, contentInsertion);
22096 //Do namespace last so that ui does not mess upthe parenRange
22098 if (namespace && !info.namespaceExists) {
22099 modLine(info.defineLoc, namespace + '.');
22102 //Notify any listener for the found info
22108 contents = contentLines.join('\n');
22110 if (options.useSourceUrl) {
22111 contents = 'eval("' + lang.jsEscape(contents) +
22112 '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') +
22121 * Modify the contents of a require.config/requirejs.config call. This
22122 * call will LOSE any existing comments that are in the config string.
22124 * @param {String} fileContents String that may contain a config call
22125 * @param {Function} onConfig Function called when the first config
22126 * call is found. It will be passed an Object which is the current
22127 * config, and the onConfig function should return an Object to use
22129 * @return {String} the fileContents with the config changes applied.
22131 modifyConfig: function (fileContents, onConfig) {
22132 var details = parse.findConfig(fileContents),
22133 config = details.config;
22136 config = onConfig(config);
22138 return transform.serializeConfig(config,
22143 quote: details.quote
22148 return fileContents;
22151 serializeConfig: function (config, fileContents, start, end, options) {
22152 //Calculate base level of indent
22153 var indent, match, configString, outDentRegExp,
22155 startString = fileContents.substring(0, start),
22156 existingConfigString = fileContents.substring(start, end),
22157 lineReturn = existingConfigString.indexOf('\r') === -1 ? '\n' : '\r\n',
22158 lastReturnIndex = startString.lastIndexOf('\n');
22160 //Get the basic amount of indent for the require config call.
22161 if (lastReturnIndex === -1) {
22162 lastReturnIndex = 0;
22165 match = baseIndentRegExp.exec(startString.substring(lastReturnIndex + 1, start));
22166 if (match && match[1]) {
22167 baseIndent = match[1];
22170 //Calculate internal indentation for config
22171 match = indentRegExp.exec(existingConfigString);
22172 if (match && match[1]) {
22176 if (!indent || indent.length < baseIndent) {
22179 indent = indent.substring(baseIndent.length);
22182 outDentRegExp = new RegExp('(' + lineReturn + ')' + indent, 'g');
22184 configString = transform.objectToString(config, {
22186 lineReturn: lineReturn,
22187 outDentRegExp: outDentRegExp,
22188 quote: options && options.quote
22191 //Add in the base indenting level.
22192 configString = applyIndent(configString, baseIndent, lineReturn);
22194 return startString + configString + fileContents.substring(end);
22198 * Tries converting a JS object to a string. This will likely suck, and
22199 * is tailored to the type of config expected in a loader config call.
22200 * So, hasOwnProperty fields, strings, numbers, arrays and functions,
22201 * no weird recursively referenced stuff.
22202 * @param {Object} obj the object to convert
22203 * @param {Object} options options object with the following values:
22204 * {String} indent the indentation to use for each level
22205 * {String} lineReturn the type of line return to use
22206 * {outDentRegExp} outDentRegExp the regexp to use to outdent functions
22207 * {String} quote the quote type to use, ' or ". Optional. Default is "
22208 * @param {String} totalIndent the total indent to print for this level
22209 * @return {String} a string representation of the object.
22211 objectToString: function (obj, options, totalIndent) {
22212 var startBrace, endBrace, nextIndent,
22215 lineReturn = options.lineReturn,
22216 indent = options.indent,
22217 outDentRegExp = options.outDentRegExp,
22218 quote = options.quote || '"';
22220 totalIndent = totalIndent || '';
22221 nextIndent = totalIndent + indent;
22223 if (obj === null) {
22225 } else if (obj === undefined) {
22226 value = 'undefined';
22227 } else if (typeof obj === 'number' || typeof obj === 'boolean') {
22229 } else if (typeof obj === 'string') {
22230 //Use double quotes in case the config may also work as JSON.
22231 value = quote + lang.jsEscape(obj) + quote;
22232 } else if (lang.isArray(obj)) {
22233 lang.each(obj, function (item, i) {
22234 value += (i !== 0 ? ',' + lineReturn : '' ) +
22236 transform.objectToString(item,
22243 } else if (lang.isFunction(obj) || lang.isRegExp(obj)) {
22244 //The outdent regexp just helps pretty up the conversion
22245 //just in node. Rhino strips comments and does a different
22246 //indent scheme for Function toString, so not really helpful
22248 value = obj.toString().replace(outDentRegExp, '$1');
22251 lang.eachProp(obj, function (v, prop) {
22252 value += (first ? '': ',' + lineReturn) +
22254 (keyRegExp.test(prop) ? prop : quote + lang.jsEscape(prop) + quote )+
22256 transform.objectToString(v,
22266 value = startBrace +
22269 lineReturn + totalIndent +
22280 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
22281 * Available via the MIT or new BSD license.
22282 * see: http://github.com/jrburke/requirejs for details
22285 /*jslint regexp: true, plusplus: true */
22286 /*global define: false */
22288 define('pragma', ['parse', 'logger'], function (parse, logger) {
22292 function create(obj, mixin) {
22293 Temp.prototype = obj;
22294 var temp = new Temp(), prop;
22296 //Avoid any extra memory hanging around
22297 Temp.prototype = null;
22300 for (prop in mixin) {
22301 if (mixin.hasOwnProperty(prop) && !temp.hasOwnProperty(prop)) {
22302 temp[prop] = mixin[prop];
22307 return temp; // Object
22311 conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/,
22312 useStrictRegExp: /['"]use strict['"];/g,
22313 hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
22314 configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g,
22315 nsWrapRegExp: /\/\*requirejs namespace: true \*\//,
22316 apiDefRegExp: /var requirejs, require, define;/,
22317 defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g,
22318 defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g,
22319 defineTypeFirstCheckRegExp: /\s*["']function["']\s*===\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g,
22320 defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g,
22321 defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
22322 defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/,
22323 amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*'function'\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g,
22325 removeStrict: function (contents, config) {
22326 return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, '');
22329 namespace: function (fileContents, ns, onLifecycleName) {
22331 //Namespace require/define calls
22332 fileContents = fileContents.replace(pragma.configRegExp, '$1' + ns + '.$2$3(');
22335 fileContents = parse.renameNamespace(fileContents, ns);
22337 //Namespace define ternary use:
22338 fileContents = fileContents.replace(pragma.defineTernaryRegExp,
22339 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd ? " + ns + ".define");
22341 //Namespace define jquery use:
22342 fileContents = fileContents.replace(pragma.defineJQueryRegExp,
22343 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd && " + ns + ".define.amd.jQuery");
22345 //Namespace has.js define use:
22346 fileContents = fileContents.replace(pragma.defineHasRegExp,
22347 "typeof " + ns + ".define === 'function' && typeof " + ns + ".define.amd === 'object' && " + ns + ".define.amd");
22349 //Namespace define checks.
22350 //Do these ones last, since they are a subset of the more specific
22352 fileContents = fileContents.replace(pragma.defineCheckRegExp,
22353 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd");
22354 fileContents = fileContents.replace(pragma.defineStringCheckRegExp,
22355 "typeof " + ns + ".define === 'function' && " + ns + ".define['amd']");
22356 fileContents = fileContents.replace(pragma.defineTypeFirstCheckRegExp,
22357 "'function' === typeof " + ns + ".define && " + ns + ".define.amd");
22359 //Check for require.js with the require/define definitions
22360 if (pragma.apiDefRegExp.test(fileContents) &&
22361 fileContents.indexOf("if (!" + ns + " || !" + ns + ".requirejs)") === -1) {
22362 //Wrap the file contents in a typeof check, and a function
22363 //to contain the API globals.
22364 fileContents = "var " + ns + ";(function () { if (!" + ns + " || !" + ns + ".requirejs) {\n" +
22365 "if (!" + ns + ") { " + ns + ' = {}; } else { require = ' + ns + '; }\n' +
22368 ns + ".requirejs = requirejs;" +
22369 ns + ".require = require;" +
22370 ns + ".define = define;\n" +
22374 //Finally, if the file wants a special wrapper because it ties
22375 //in to the requirejs internals in a way that would not fit
22376 //the above matches, do that. Look for /*requirejs namespace: true*/
22377 if (pragma.nsWrapRegExp.test(fileContents)) {
22378 //Remove the pragma.
22379 fileContents = fileContents.replace(pragma.nsWrapRegExp, '');
22381 //Alter the contents.
22382 fileContents = '(function () {\n' +
22383 'var require = ' + ns + '.require,' +
22384 'requirejs = ' + ns + '.requirejs,' +
22385 'define = ' + ns + '.define;\n' +
22391 return fileContents;
22395 * processes the fileContents for some //>> conditional statements
22397 process: function (fileName, fileContents, config, onLifecycleName, pluginCollector) {
22398 /*jslint evil: true */
22399 var foundIndex = -1, startIndex = 0, lineEndIndex, conditionLine,
22400 matches, type, marker, condition, isTrue, endRegExp, endMatches,
22401 endMarkerIndex, shouldInclude, startLength, lifecycleHas, deps,
22402 i, dep, moduleName, collectorMod,
22403 lifecyclePragmas, pragmas = config.pragmas, hasConfig = config.has,
22404 //Legacy arg defined to help in dojo conversion script. Remove later
22405 //when dojo no longer needs conversion:
22408 //Mix in a specific lifecycle scoped object, to allow targeting
22409 //some pragmas/has tests to only when files are saved, or at different
22410 //lifecycle events. Do not bother with kwArgs in this section, since
22411 //the old dojo kwArgs were for all points in the build lifecycle.
22412 if (onLifecycleName) {
22413 lifecyclePragmas = config['pragmas' + onLifecycleName];
22414 lifecycleHas = config['has' + onLifecycleName];
22416 if (lifecyclePragmas) {
22417 pragmas = create(pragmas || {}, lifecyclePragmas);
22420 if (lifecycleHas) {
22421 hasConfig = create(hasConfig || {}, lifecycleHas);
22425 //Replace has references if desired
22427 fileContents = fileContents.replace(pragma.hasRegExp, function (match, test) {
22428 if (hasConfig.hasOwnProperty(test)) {
22429 return !!hasConfig[test];
22435 if (!config.skipPragmas) {
22437 while ((foundIndex = fileContents.indexOf("//>>", startIndex)) !== -1) {
22438 //Found a conditional. Get the conditional line.
22439 lineEndIndex = fileContents.indexOf("\n", foundIndex);
22440 if (lineEndIndex === -1) {
22441 lineEndIndex = fileContents.length - 1;
22444 //Increment startIndex past the line so the next conditional search can be done.
22445 startIndex = lineEndIndex + 1;
22447 //Break apart the conditional.
22448 conditionLine = fileContents.substring(foundIndex, lineEndIndex + 1);
22449 matches = conditionLine.match(pragma.conditionalRegExp);
22452 marker = matches[2];
22453 condition = matches[3];
22455 //See if the condition is true.
22457 isTrue = !!eval("(" + condition + ")");
22459 throw "Error in file: " +
22461 ". Conditional comment: " +
22463 " failed with this error: " + e;
22466 //Find the endpoint marker.
22467 endRegExp = new RegExp('\\/\\/\\>\\>\\s*' + type + 'End\\(\\s*[\'"]' + marker + '[\'"]\\s*\\)', "g");
22468 endMatches = endRegExp.exec(fileContents.substring(startIndex, fileContents.length));
22470 endMarkerIndex = startIndex + endRegExp.lastIndex - endMatches[0].length;
22472 //Find the next line return based on the match position.
22473 lineEndIndex = fileContents.indexOf("\n", endMarkerIndex);
22474 if (lineEndIndex === -1) {
22475 lineEndIndex = fileContents.length - 1;
22478 //Should we include the segment?
22479 shouldInclude = ((type === "exclude" && !isTrue) || (type === "include" && isTrue));
22481 //Remove the conditional comments, and optionally remove the content inside
22482 //the conditional comments.
22483 startLength = startIndex - foundIndex;
22484 fileContents = fileContents.substring(0, foundIndex) +
22485 (shouldInclude ? fileContents.substring(startIndex, endMarkerIndex) : "") +
22486 fileContents.substring(lineEndIndex + 1, fileContents.length);
22488 //Move startIndex to foundIndex, since that is the new position in the file
22489 //where we need to look for more conditionals in the next while loop pass.
22490 startIndex = foundIndex;
22492 throw "Error in file: " +
22494 ". Cannot find end marker for conditional comment: " +
22502 //If need to find all plugin resources to optimize, do that now,
22503 //before namespacing, since the namespacing will change the API
22505 //If there is a plugin collector, scan the file for plugin resources.
22506 if (config.optimizeAllPluginResources && pluginCollector) {
22508 deps = parse.findDependencies(fileName, fileContents);
22510 for (i = 0; i < deps.length; i++) {
22512 if (dep.indexOf('!') !== -1) {
22513 moduleName = dep.split('!')[0];
22514 collectorMod = pluginCollector[moduleName];
22515 if (!collectorMod) {
22516 collectorMod = pluginCollector[moduleName] = [];
22518 collectorMod.push(dep);
22523 logger.error('Parse error looking for plugin resources in ' +
22524 fileName + ', skipping.');
22528 //Strip amdefine use for node-shared modules.
22529 fileContents = fileContents.replace(pragma.amdefineRegExp, '');
22532 if (onLifecycleName === 'OnSave' && config.namespace) {
22533 fileContents = pragma.namespace(fileContents, config.namespace, onLifecycleName);
22537 return pragma.removeStrict(fileContents, config);
22543 if(env === 'browser') {
22545 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
22546 * Available via the MIT or new BSD license.
22547 * see: http://github.com/jrburke/requirejs for details
22550 /*jslint strict: false */
22551 /*global define: false */
22553 define('browser/optimize', {});
22557 if(env === 'node') {
22559 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
22560 * Available via the MIT or new BSD license.
22561 * see: http://github.com/jrburke/requirejs for details
22564 /*jslint strict: false */
22565 /*global define: false */
22567 define('node/optimize', {});
22571 if(env === 'rhino') {
22573 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
22574 * Available via the MIT or new BSD license.
22575 * see: http://github.com/jrburke/requirejs for details
22578 /*jslint sloppy: true, plusplus: true */
22579 /*global define, java, Packages, com */
22581 define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) {
22583 //Add .reduce to Rhino so UglifyJS can run in Rhino,
22584 //inspired by https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
22585 //but rewritten for brevity, and to be good enough for use by UglifyJS.
22586 if (!Array.prototype.reduce) {
22587 Array.prototype.reduce = function (fn /*, initialValue */) {
22589 length = this.length,
22592 if (arguments.length >= 2) {
22593 accumulator = arguments[1];
22596 while (!(i in this)) {
22599 accumulator = this[i++];
22603 for (; i < length; i++) {
22605 accumulator = fn.call(undefined, accumulator, this[i], i, this);
22609 return accumulator;
22613 var JSSourceFilefromCode, optimize,
22614 mapRegExp = /"file":"[^"]+"/;
22616 //Bind to Closure compiler, but if it is not available, do not sweat it.
22618 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.JSSourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]);
22621 //Helper for closure compiler, because of weird Java-JavaScript interactions.
22622 function closurefromCode(filename, content) {
22623 return JSSourceFilefromCode.invoke(null, [filename, content]);
22627 function getFileWriter(fileName, encoding) {
22628 var outFile = new java.io.File(fileName), outWriter, parentDir;
22630 parentDir = outFile.getAbsoluteFile().getParentFile();
22631 if (!parentDir.exists()) {
22632 if (!parentDir.mkdirs()) {
22633 throw "Could not create directory: " + parentDir.getAbsolutePath();
22638 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
22640 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
22643 return new java.io.BufferedWriter(outWriter);
22647 closure: function (fileName, fileContents, outFileName, keepLines, config) {
22648 config = config || {};
22649 var result, mappings, optimized, compressed, baseName, writer,
22650 outBaseName, outFileNameMap, outFileNameMapContent,
22651 jscomp = Packages.com.google.javascript.jscomp,
22652 flags = Packages.com.google.common.flags,
22654 externSourceFile = closurefromCode("fakeextern.js", " "),
22655 //Set up source input
22656 jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
22657 options, option, FLAG_compilation_level, compiler,
22658 Compiler = Packages.com.google.javascript.jscomp.Compiler;
22660 logger.trace("Minifying file: " + fileName);
22662 baseName = (new java.io.File(fileName)).getName();
22665 options = new jscomp.CompilerOptions();
22666 for (option in config.CompilerOptions) {
22667 // options are false by default and jslint wanted an if statement in this for loop
22668 if (config.CompilerOptions[option]) {
22669 options[option] = config.CompilerOptions[option];
22673 options.prettyPrint = keepLines || options.prettyPrint;
22675 FLAG_compilation_level = jscomp.CompilationLevel[config.CompilationLevel || 'SIMPLE_OPTIMIZATIONS'];
22676 FLAG_compilation_level.setOptionsForCompilationLevel(options);
22678 if (config.generateSourceMaps) {
22679 mappings = new java.util.ArrayList();
22681 mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src"));
22682 options.setSourceMapLocationMappings(mappings);
22683 options.setSourceMapOutputPath(fileName + ".map");
22686 //Trigger the compiler
22687 Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']);
22688 compiler = new Compiler();
22690 result = compiler.compile(externSourceFile, jsSourceFile, options);
22691 if (result.success) {
22692 optimized = String(compiler.toSource());
22694 if (config.generateSourceMaps && result.sourceMap && outFileName) {
22695 outBaseName = (new java.io.File(outFileName)).getName();
22697 file.saveUtf8File(outFileName + ".src", fileContents);
22699 outFileNameMap = outFileName + ".map";
22700 writer = getFileWriter(outFileNameMap, "utf-8");
22701 result.sourceMap.appendTo(writer, outFileName);
22704 //Not sure how better to do this, but right now the .map file
22705 //leaks the full OS path in the "file" property. Manually
22706 //modify it to not do that.
22707 file.saveFile(outFileNameMap,
22708 file.readFile(outFileNameMap).replace(mapRegExp, '"file":"' + baseName + '"'));
22710 fileContents = optimized + "\n//# sourceMappingURL=" + outBaseName + ".map";
22712 fileContents = optimized;
22714 return fileContents;
22716 throw new Error('Cannot closure compile file: ' + fileName + '. Skipping it.');
22719 return fileContents;
22727 if(env === 'xpconnect') {
22728 define('xpconnect/optimize', {});
22731 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
22732 * Available via the MIT or new BSD license.
22733 * see: http://github.com/jrburke/requirejs for details
22736 /*jslint plusplus: true, nomen: true, regexp: true */
22737 /*global define: false */
22739 define('optimize', [ 'lang', 'logger', 'env!env/optimize', 'env!env/file', 'parse',
22740 'pragma', 'uglifyjs/index', 'uglifyjs2',
22742 function (lang, logger, envOptimize, file, parse,
22743 pragma, uglify, uglify2,
22748 cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig,
22749 cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g,
22750 cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g,
22751 SourceMapGenerator = sourceMap.SourceMapGenerator,
22752 SourceMapConsumer =sourceMap.SourceMapConsumer;
22755 * If an URL from a CSS url value contains start/end quotes, remove them.
22756 * This is not done in the regexp, since my regexp fu is not that strong,
22757 * and the CSS spec allows for ' and " in the URL if they are backslash escaped.
22758 * @param {String} url
22760 function cleanCssUrlQuotes(url) {
22761 //Make sure we are not ending in whitespace.
22762 //Not very confident of the css regexps above that there will not be ending
22764 url = url.replace(/\s+$/, "");
22766 if (url.charAt(0) === "'" || url.charAt(0) === "\"") {
22767 url = url.substring(1, url.length - 1);
22774 * Inlines nested stylesheets that have @import calls in them.
22775 * @param {String} fileName the file name
22776 * @param {String} fileContents the file contents
22777 * @param {String} cssImportIgnore comma delimited string of files to ignore
22778 * @param {String} cssPrefix string to be prefixed before relative URLs
22779 * @param {Object} included an object used to track the files already imported
22781 function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included) {
22782 //Find the last slash in the name.
22783 fileName = fileName.replace(lang.backSlashRegExp, "/");
22784 var endIndex = fileName.lastIndexOf("/"),
22785 //Make a file path based on the last slash.
22786 //If no slash, so must be just a file name. Use empty string then.
22787 filePath = (endIndex !== -1) ? fileName.substring(0, endIndex + 1) : "",
22788 //store a list of merged files
22792 //First make a pass by removing an commented out @import calls.
22793 fileContents = fileContents.replace(cssCommentImportRegExp, '');
22795 //Make sure we have a delimited ignore list to make matching faster
22796 if (cssImportIgnore && cssImportIgnore.charAt(cssImportIgnore.length - 1) !== ",") {
22797 cssImportIgnore += ",";
22800 fileContents = fileContents.replace(cssImportRegExp, function (fullMatch, urlStart, importFileName, urlEnd, mediaTypes) {
22801 //Only process media type "all" or empty media type rules.
22802 if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) {
22803 skippedList.push(fileName);
22807 importFileName = cleanCssUrlQuotes(importFileName);
22809 //Ignore the file import if it is part of an ignore list.
22810 if (cssImportIgnore && cssImportIgnore.indexOf(importFileName + ",") !== -1) {
22814 //Make sure we have a unix path for the rest of the operation.
22815 importFileName = importFileName.replace(lang.backSlashRegExp, "/");
22818 //if a relative path, then tack on the filePath.
22819 //If it is not a relative path, then the readFile below will fail,
22820 //and we will just skip that import.
22821 var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName,
22822 importContents = file.readFile(fullImportFileName), i,
22823 importEndIndex, importPath, fixedUrlMatch, colonIndex, parts, flat;
22825 //Skip the file if it has already been included.
22826 if (included[fullImportFileName]) {
22829 included[fullImportFileName] = true;
22831 //Make sure to flatten any nested imports.
22832 flat = flattenCss(fullImportFileName, importContents, cssImportIgnore, cssPrefix, included);
22833 importContents = flat.fileContents;
22835 if (flat.importList.length) {
22836 importList.push.apply(importList, flat.importList);
22838 if (flat.skippedList.length) {
22839 skippedList.push.apply(skippedList, flat.skippedList);
22842 //Make the full import path
22843 importEndIndex = importFileName.lastIndexOf("/");
22845 //Make a file path based on the last slash.
22846 //If no slash, so must be just a file name. Use empty string then.
22847 importPath = (importEndIndex !== -1) ? importFileName.substring(0, importEndIndex + 1) : "";
22849 //fix url() on relative import (#5)
22850 importPath = importPath.replace(/^\.\//, '');
22852 //Modify URL paths to match the path represented by this file.
22853 importContents = importContents.replace(cssUrlRegExp, function (fullMatch, urlMatch) {
22854 fixedUrlMatch = cleanCssUrlQuotes(urlMatch);
22855 fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/");
22857 //Only do the work for relative URLs. Skip things that start with / or have
22859 colonIndex = fixedUrlMatch.indexOf(":");
22860 if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) {
22861 //It is a relative URL, tack on the cssPrefix and path prefix
22862 urlMatch = cssPrefix + importPath + fixedUrlMatch;
22865 logger.trace(importFileName + "\n URL not a relative URL, skipping: " + urlMatch);
22868 //Collapse .. and .
22869 parts = urlMatch.split("/");
22870 for (i = parts.length - 1; i > 0; i--) {
22871 if (parts[i] === ".") {
22872 parts.splice(i, 1);
22873 } else if (parts[i] === "..") {
22874 if (i !== 0 && parts[i - 1] !== "..") {
22875 parts.splice(i - 1, 2);
22881 return "url(" + parts.join("/") + ")";
22884 importList.push(fullImportFileName);
22885 return importContents;
22887 logger.warn(fileName + "\n Cannot inline css import, skipping: " + importFileName);
22893 importList : importList,
22894 skippedList: skippedList,
22895 fileContents : fileContents
22901 * Optimizes a file that contains JavaScript content. Optionally collects
22902 * plugin resources mentioned in a file, and then passes the content
22903 * through an minifier if one is specified via config.optimize.
22905 * @param {String} fileName the name of the file to optimize
22906 * @param {String} fileContents the contents to optimize. If this is
22907 * a null value, then fileName will be used to read the fileContents.
22908 * @param {String} outFileName the name of the file to use for the
22909 * saved optimized content.
22910 * @param {Object} config the build config object.
22911 * @param {Array} [pluginCollector] storage for any plugin resources
22914 jsFile: function (fileName, fileContents, outFileName, config, pluginCollector) {
22915 if (!fileContents) {
22916 fileContents = file.readFile(fileName);
22919 fileContents = optimize.js(fileName, fileContents, outFileName, config, pluginCollector);
22921 file.saveUtf8File(outFileName, fileContents);
22925 * Optimizes a file that contains JavaScript content. Optionally collects
22926 * plugin resources mentioned in a file, and then passes the content
22927 * through an minifier if one is specified via config.optimize.
22929 * @param {String} fileName the name of the file that matches the
22931 * @param {String} fileContents the string of JS to optimize.
22932 * @param {Object} [config] the build config object.
22933 * @param {Array} [pluginCollector] storage for any plugin resources
22936 js: function (fileName, fileContents, outFileName, config, pluginCollector) {
22937 var optFunc, optConfig,
22938 parts = (String(config.optimize)).split('.'),
22939 optimizerName = parts[0],
22940 keepLines = parts[1] === 'keepLines',
22941 licenseContents = '';
22943 config = config || {};
22945 //Apply pragmas/namespace renaming
22946 fileContents = pragma.process(fileName, fileContents, config, 'OnSave', pluginCollector);
22948 //Optimize the JS files if asked.
22949 if (optimizerName && optimizerName !== 'none') {
22950 optFunc = envOptimize[optimizerName] || optimize.optimizers[optimizerName];
22952 throw new Error('optimizer with name of "' +
22954 '" not found for this environment');
22957 optConfig = config[optimizerName] || {};
22958 if (config.generateSourceMaps) {
22959 optConfig.generateSourceMaps = !!config.generateSourceMaps;
22963 if (config.preserveLicenseComments) {
22964 //Pull out any license comments for prepending after optimization.
22966 licenseContents = parse.getLicenseComments(fileName, fileContents);
22968 throw new Error('Cannot parse file: ' + fileName + ' for comments. Skipping it. Error is:\n' + e.toString());
22972 fileContents = licenseContents + optFunc(fileName,
22978 if (config.throwWhen && config.throwWhen.optimize) {
22986 return fileContents;
22990 * Optimizes one CSS file, inlining @import calls, stripping comments, and
22991 * optionally removes line returns.
22992 * @param {String} fileName the path to the CSS file to optimize
22993 * @param {String} outFileName the path to save the optimized file.
22994 * @param {Object} config the config object with the optimizeCss and
22995 * cssImportIgnore options.
22997 cssFile: function (fileName, outFileName, config) {
22999 //Read in the file. Make sure we have a JS string.
23000 var originalFileContents = file.readFile(fileName),
23001 flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}),
23002 //Do not use the flattened CSS if there was one that was skipped.
23003 fileContents = flat.skippedList.length ? originalFileContents : flat.fileContents,
23004 startIndex, endIndex, buildText, comment;
23006 if (flat.skippedList.length) {
23007 logger.warn('Cannot inline @imports for ' + fileName +
23008 ',\nthe following files had media queries in them:\n' +
23009 flat.skippedList.join('\n'));
23012 //Do comment removal.
23014 if (config.optimizeCss.indexOf(".keepComments") === -1) {
23016 //Get rid of comments.
23017 while ((startIndex = fileContents.indexOf("/*", startIndex)) !== -1) {
23018 endIndex = fileContents.indexOf("*/", startIndex + 2);
23019 if (endIndex === -1) {
23020 throw "Improper comment in CSS file: " + fileName;
23022 comment = fileContents.substring(startIndex, endIndex);
23024 if (config.preserveLicenseComments &&
23025 (comment.indexOf('license') !== -1 ||
23026 comment.indexOf('opyright') !== -1 ||
23027 comment.indexOf('(c)') !== -1)) {
23028 //Keep the comment, just increment the startIndex
23029 startIndex = endIndex;
23031 fileContents = fileContents.substring(0, startIndex) + fileContents.substring(endIndex + 2, fileContents.length);
23036 //Get rid of newlines.
23037 if (config.optimizeCss.indexOf(".keepLines") === -1) {
23038 fileContents = fileContents.replace(/[\r\n]/g, "");
23039 fileContents = fileContents.replace(/\s+/g, " ");
23040 fileContents = fileContents.replace(/\{\s/g, "{");
23041 fileContents = fileContents.replace(/\s\}/g, "}");
23043 //Remove multiple empty lines.
23044 fileContents = fileContents.replace(/(\r\n)+/g, "\r\n");
23045 fileContents = fileContents.replace(/(\n)+/g, "\n");
23048 fileContents = originalFileContents;
23049 logger.error("Could not optimized CSS file: " + fileName + ", error: " + e);
23052 file.saveUtf8File(outFileName, fileContents);
23054 //text output to stdout and/or written to build.txt file
23055 buildText = "\n"+ outFileName.replace(config.dir, "") +"\n----------------\n";
23056 flat.importList.push(fileName);
23057 buildText += flat.importList.map(function(path){
23058 return path.replace(config.dir, "");
23062 importList: flat.importList,
23063 buildText: buildText +"\n"
23068 * Optimizes CSS files, inlining @import calls, stripping comments, and
23069 * optionally removes line returns.
23070 * @param {String} startDir the path to the top level directory
23071 * @param {Object} config the config object with the optimizeCss and
23072 * cssImportIgnore options.
23074 css: function (startDir, config) {
23075 var buildText = "",
23077 shouldRemove = config.dir && config.removeCombined,
23078 i, fileName, result, fileList;
23079 if (config.optimizeCss.indexOf("standard") !== -1) {
23080 fileList = file.getFilteredFileList(startDir, /\.css$/, true);
23082 for (i = 0; i < fileList.length; i++) {
23083 fileName = fileList[i];
23084 logger.trace("Optimizing (" + config.optimizeCss + ") CSS file: " + fileName);
23085 result = optimize.cssFile(fileName, fileName, config);
23086 buildText += result.buildText;
23087 if (shouldRemove) {
23088 result.importList.pop();
23089 importList = importList.concat(result.importList);
23094 if (shouldRemove) {
23095 importList.forEach(function (path) {
23096 if (file.exists(path)) {
23097 file.deleteFile(path);
23106 uglify: function (fileName, fileContents, outFileName, keepLines, config) {
23107 var parser = uglify.parser,
23108 processor = uglify.uglify,
23109 ast, errMessage, errMatch;
23111 config = config || {};
23113 logger.trace("Uglifying file: " + fileName);
23116 ast = parser.parse(fileContents, config.strict_semicolons);
23117 if (config.no_mangle !== true) {
23118 ast = processor.ast_mangle(ast, config);
23120 ast = processor.ast_squeeze(ast, config);
23122 fileContents = processor.gen_code(ast, config);
23124 if (config.max_line_length) {
23125 fileContents = processor.split_lines(fileContents, config.max_line_length);
23128 //Add trailing semicolon to match uglifyjs command line version
23129 fileContents += ';';
23131 errMessage = e.toString();
23132 errMatch = /\nError(\r)?\n/.exec(errMessage);
23134 errMessage = errMessage.substring(0, errMatch.index);
23136 throw new Error('Cannot uglify file: ' + fileName + '. Skipping it. Error is:\n' + errMessage);
23138 return fileContents;
23140 uglify2: function (fileName, fileContents, outFileName, keepLines, config) {
23141 var result, existingMap, resultMap, finalMap, sourceIndex,
23143 existingMapPath = outFileName + '.map',
23144 baseName = fileName && fileName.split('/').pop();
23146 config = config || {};
23148 lang.mixin(uconfig, config, true);
23150 uconfig.fromString = true;
23152 if (config.generateSourceMaps && outFileName) {
23153 uconfig.outSourceMap = baseName;
23155 if (file.exists(existingMapPath)) {
23156 uconfig.inSourceMap = existingMapPath;
23157 existingMap = JSON.parse(file.readFile(existingMapPath));
23161 logger.trace("Uglify2 file: " + fileName);
23164 //var tempContents = fileContents.replace(/\/\/\# sourceMappingURL=.*$/, '');
23165 result = uglify2.minify(fileContents, uconfig, baseName + '.src.js');
23166 if (uconfig.outSourceMap && result.map) {
23167 resultMap = result.map;
23169 resultMap = JSON.parse(resultMap);
23170 finalMap = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(resultMap));
23171 finalMap.applySourceMap(new SourceMapConsumer(existingMap));
23172 resultMap = finalMap.toString();
23174 file.saveFile(outFileName + '.src.js', fileContents);
23176 file.saveFile(outFileName + '.map', resultMap);
23177 fileContents = result.code + "\n//# sourceMappingURL=" + baseName + ".map";
23179 fileContents = result.code;
23182 throw new Error('Cannot uglify2 file: ' + fileName + '. Skipping it. Error is:\n' + e.toString());
23184 return fileContents;
23192 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
23193 * Available via the MIT or new BSD license.
23194 * see: http://github.com/jrburke/requirejs for details
23197 * This file patches require.js to communicate with the build system.
23200 //Using sloppy since this uses eval for some code like plugins,
23201 //which may not be strict mode compliant. So if use strict is used
23202 //below they will have strict rules applied and may cause an error.
23203 /*jslint sloppy: true, nomen: true, plusplus: true, regexp: true */
23204 /*global require, define: true */
23206 //NOT asking for require as a dependency since the goal is to modify the
23207 //global require below
23208 define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim'], function (
23218 var allowRun = true,
23219 hasProp = lang.hasProp,
23220 falseProp = lang.falseProp,
23221 getOwn = lang.getOwn;
23223 //This method should be called when the patches to require should take hold.
23224 return function () {
23231 pluginBuilderRegExp = /(["']?)pluginBuilder(["']?)\s*[=\:]\s*["']([^'"\s]+)["']/,
23232 oldNewContext = require.s.newContext,
23235 //create local undefined values for module and exports,
23236 //so that when files are evaled in this function they do not
23237 //see the node values used for r.js
23242 * Reset "global" build caches that are kept around between
23243 * build layer builds. Useful to do when there are multiple
23244 * top level requirejs.optimize() calls.
23246 require._cacheReset = function () {
23247 //Stored raw text caches, used by browser use.
23248 require._cachedRawText = {};
23249 //Stored cached file contents for reuse in other layers.
23250 require._cachedFileContents = {};
23251 //Store which cached files contain a require definition.
23252 require._cachedDefinesRequireUrls = {};
23254 require._cacheReset();
23257 * Makes sure the URL is something that can be supported by the
23258 * optimization tool.
23259 * @param {String} url
23260 * @returns {Boolean}
23262 require._isSupportedBuildUrl = function (url) {
23263 //Ignore URLs with protocols, hosts or question marks, means either network
23264 //access is needed to fetch it or it is too dynamic. Note that
23265 //on Windows, full paths are used for some urls, which include
23266 //the drive, like c:/something, so need to test for something other
23267 //than just a colon.
23268 if (url.indexOf("://") === -1 && url.indexOf("?") === -1 &&
23269 url.indexOf('empty:') !== 0 && url.indexOf('//') !== 0) {
23272 if (!layer.ignoredUrls[url]) {
23273 if (url.indexOf('empty:') === -1) {
23274 logger.info('Cannot optimize network URL, skipping: ' + url);
23276 layer.ignoredUrls[url] = true;
23282 function normalizeUrlWithBase(context, moduleName, url) {
23283 //Adjust the URL if it was not transformed to use baseUrl.
23284 if (require.jsExtRegExp.test(moduleName)) {
23285 url = (context.config.dir || context.config.dirBaseUrl) + url;
23290 //Overrides the new context call to add existing tracking features.
23291 require.s.newContext = function (name) {
23292 var context = oldNewContext(name),
23293 oldEnable = context.enable,
23294 moduleProto = context.Module.prototype,
23295 oldInit = moduleProto.init,
23296 oldCallPlugin = moduleProto.callPlugin;
23298 //Only do this for the context used for building.
23299 if (name === '_') {
23300 //For build contexts, do everything sync
23301 context.nextTick = function (fn) {
23305 context.needFullExec = {};
23306 context.fullExec = {};
23307 context.plugins = {};
23308 context.buildShimExports = {};
23310 //Override the shim exports function generator to just
23311 //spit out strings that can be used in the stringified
23313 context.makeShimExports = function (value) {
23315 return '(function (global) {\n' +
23316 ' return function () {\n' +
23317 ' var ret, fn;\n' +
23319 (' fn = ' + value.init.toString() + ';\n' +
23320 ' ret = fn.apply(global, arguments);\n') : '') +
23322 ' return ret || global.' + value.exports + ';\n' :
23323 ' return ret;\n') +
23331 context.enable = function (depMap, parent) {
23332 var id = depMap.id,
23333 parentId = parent && parent.map.id,
23334 needFullExec = context.needFullExec,
23335 fullExec = context.fullExec,
23336 mod = getOwn(context.registry, id);
23338 if (mod && !mod.defined) {
23339 if (parentId && getOwn(needFullExec, parentId)) {
23340 needFullExec[id] = true;
23343 } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) ||
23344 (parentId && getOwn(needFullExec, parentId) &&
23345 falseProp(fullExec, id))) {
23346 context.require.undef(id);
23349 return oldEnable.apply(context, arguments);
23352 //Override load so that the file paths can be collected.
23353 context.load = function (moduleName, url) {
23354 /*jslint evil: true */
23355 var contents, pluginBuilderMatch, builderName,
23358 //Do not mark the url as fetched if it is
23359 //not an empty: URL, used by the optimizer.
23360 //In that case we need to be sure to call
23361 //load() for each module that is mapped to
23362 //empty: so that dependencies are satisfied
23364 if (url.indexOf('empty:') === 0) {
23365 delete context.urlFetched[url];
23368 //Only handle urls that can be inlined, so that means avoiding some
23369 //URLs like ones that require network access or may be too dynamic,
23371 if (require._isSupportedBuildUrl(url)) {
23372 //Adjust the URL if it was not transformed to use baseUrl.
23373 url = normalizeUrlWithBase(context, moduleName, url);
23375 //Save the module name to path and path to module name mappings.
23376 layer.buildPathMap[moduleName] = url;
23377 layer.buildFileToModule[url] = moduleName;
23379 if (hasProp(context.plugins, moduleName)) {
23380 //plugins need to have their source evaled as-is.
23381 context.needFullExec[moduleName] = true;
23384 prim().start(function () {
23385 if (hasProp(require._cachedFileContents, url) &&
23386 (falseProp(context.needFullExec, moduleName) ||
23387 getOwn(context.fullExec, moduleName))) {
23388 contents = require._cachedFileContents[url];
23390 //If it defines require, mark it so it can be hoisted.
23391 //Done here and in the else below, before the
23392 //else block removes code from the contents.
23394 if (!layer.existingRequireUrl && require._cachedDefinesRequireUrls[url]) {
23395 layer.existingRequireUrl = url;
23398 //Load the file contents, process for conditionals, then
23400 return require._cacheReadAsync(url).then(function (text) {
23403 if (context.config.cjsTranslate &&
23404 (!context.config.shim || !lang.hasProp(context.config.shim, moduleName))) {
23405 contents = commonJs.convert(url, contents);
23408 //If there is a read filter, run it now.
23409 if (context.config.onBuildRead) {
23410 contents = context.config.onBuildRead(moduleName, url, contents);
23413 contents = pragma.process(url, contents, context.config, 'OnExecute');
23415 //Find out if the file contains a require() definition. Need to know
23416 //this so we can inject plugins right after it, but before they are needed,
23417 //and to make sure this file is first, so that define calls work.
23419 if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) {
23420 layer.existingRequireUrl = url;
23421 require._cachedDefinesRequireUrls[url] = true;
23424 throw new Error('Parse error using esprima ' +
23425 'for file: ' + url + '\n' + e1);
23427 }).then(function () {
23428 if (hasProp(context.plugins, moduleName)) {
23429 //This is a loader plugin, check to see if it has a build extension,
23430 //otherwise the plugin will act as the plugin builder too.
23431 pluginBuilderMatch = pluginBuilderRegExp.exec(contents);
23432 if (pluginBuilderMatch) {
23433 //Load the plugin builder for the plugin contents.
23434 builderName = context.makeModuleMap(pluginBuilderMatch[3],
23435 context.makeModuleMap(moduleName),
23438 return require._cacheReadAsync(context.nameToUrl(builderName));
23442 }).then(function (text) {
23445 //Parse out the require and define calls.
23446 //Do this even for plugins in case they have their own
23447 //dependencies that may be separate to how the pluginBuilder works.
23449 if (falseProp(context.needFullExec, moduleName)) {
23450 contents = parse(moduleName, url, contents, {
23451 insertNeedsDefine: true,
23452 has: context.config.has,
23453 findNestedDependencies: context.config.findNestedDependencies
23457 throw new Error('Parse error using esprima ' +
23458 'for file: ' + url + '\n' + e2);
23461 require._cachedFileContents[url] = contents;
23464 }).then(function () {
23470 //If have a string shim config, and this is
23471 //a fully executed module, try to see if
23472 //it created a variable in this eval scope
23473 if (getOwn(context.needFullExec, moduleName)) {
23474 shim = getOwn(context.config.shim, moduleName);
23475 if (shim && shim.exports) {
23476 shimExports = eval(shim.exports);
23477 if (typeof shimExports !== 'undefined') {
23478 context.buildShimExports[moduleName] = shimExports;
23483 //Need to close out completion of this module
23484 //so that listeners will get notified that it is available.
23485 context.completeLoad(moduleName);
23487 //Track which module could not complete loading.
23488 if (!e.moduleTree) {
23491 e.moduleTree.push(moduleName);
23494 }).then(null, function (eOuter) {
23496 if (!eOuter.fileName) {
23497 eOuter.fileName = url;
23502 //With unsupported URLs still need to call completeLoad to
23504 context.completeLoad(moduleName);
23508 //Marks module has having a name, and optionally executes the
23509 //callback, but only if it meets certain criteria.
23510 context.execCb = function (name, cb, args, exports) {
23511 var buildShimExports = getOwn(layer.context.buildShimExports, name);
23513 if (buildShimExports) {
23514 return buildShimExports;
23515 } else if (cb.__requireJsBuild || getOwn(layer.context.needFullExec, name)) {
23516 return cb.apply(exports, args);
23521 moduleProto.init = function (depMaps) {
23522 if (context.needFullExec[this.map.id]) {
23523 lang.each(depMaps, lang.bind(this, function (depMap) {
23524 if (typeof depMap === 'string') {
23525 depMap = context.makeModuleMap(depMap,
23526 (this.map.isDefine ? this.map : this.map.parentMap));
23529 if (!context.fullExec[depMap.id]) {
23530 context.require.undef(depMap.id);
23535 return oldInit.apply(this, arguments);
23538 moduleProto.callPlugin = function () {
23539 var map = this.map,
23540 pluginMap = context.makeModuleMap(map.prefix),
23541 pluginId = pluginMap.id,
23542 pluginMod = getOwn(context.registry, pluginId);
23544 context.plugins[pluginId] = true;
23545 context.needFullExec[pluginId] = true;
23547 //If the module is not waiting to finish being defined,
23548 //undef it and start over, to get full execution.
23549 if (falseProp(context.fullExec, pluginId) && (!pluginMod || pluginMod.defined)) {
23550 context.require.undef(pluginMap.id);
23553 return oldCallPlugin.apply(this, arguments);
23560 //Clear up the existing context so that the newContext modifications
23561 //above will be active.
23562 delete require.s.contexts._;
23564 /** Reset state for each build layer pass. */
23565 require._buildReset = function () {
23566 var oldContext = require.s.contexts._;
23568 //Clear up the existing context.
23569 delete require.s.contexts._;
23571 //Set up new context, so the layer object can hold onto it.
23574 layer = require._layer = {
23576 buildFileToModule: {},
23577 buildFilePaths: [],
23579 modulesWithNames: {},
23581 existingRequireUrl: "",
23583 context: require.s.contexts._
23586 //Return the previous context in case it is needed, like for
23587 //the basic config object.
23591 require._buildReset();
23593 //Override define() to catch modules that just define an object, so that
23594 //a dummy define call is not put in the build file for them. They do
23595 //not end up getting defined via context.execCb, so we need to catch them
23596 //at the define call.
23599 //This function signature does not have to be exact, just match what we
23601 define = function (name) {
23602 if (typeof name === "string" && falseProp(layer.needsDefine, name)) {
23603 layer.modulesWithNames[name] = true;
23605 return oldDef.apply(require, arguments);
23608 define.amd = oldDef.amd;
23610 //Add some utilities for plugins
23611 require._readFile = file.readFile;
23612 require._fileExists = function (path) {
23613 return file.exists(path);
23616 //Called when execManager runs for a dependency. Used to figure out
23617 //what order of execution.
23618 require.onResourceLoad = function (context, map) {
23622 //If build needed a full execution, indicate it
23623 //has been done now. But only do it if the context is tracking
23624 //that. Only valid for the context used in a build, not for
23625 //other contexts being run, like for useLib, plain requirejs
23626 //use in node/rhino.
23627 if (context.needFullExec && getOwn(context.needFullExec, id)) {
23628 context.fullExec[id] = true;
23633 if (falseProp(layer.pathAdded, id)) {
23634 layer.buildFilePaths.push(id);
23635 //For plugins the real path is not knowable, use the name
23636 //for both module to file and file to module mappings.
23637 layer.buildPathMap[id] = id;
23638 layer.buildFileToModule[id] = id;
23639 layer.modulesWithNames[id] = true;
23640 layer.pathAdded[id] = true;
23642 } else if (map.url && require._isSupportedBuildUrl(map.url)) {
23643 //If the url has not been added to the layer yet, and it
23644 //is from an actual file that was loaded, add it now.
23645 url = normalizeUrlWithBase(context, id, map.url);
23646 if (!layer.pathAdded[url] && getOwn(layer.buildPathMap, id)) {
23647 //Remember the list of dependencies for this layer.
23648 layer.buildFilePaths.push(url);
23649 layer.pathAdded[url] = true;
23654 //Called by output of the parse() function, when a file does not
23655 //explicitly call define, probably just require, but the parse()
23656 //function normalizes on define() for dependency mapping and file
23657 //ordering works correctly.
23658 require.needsDefine = function (moduleName) {
23659 layer.needsDefine[moduleName] = true;
23664 * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
23665 * Available via the MIT or new BSD license.
23666 * see: http://github.com/jrburke/requirejs for details
23670 /*global define: false, console: false */
23672 define('commonJs', ['env!env/file', 'parse'], function (file, parse) {
23675 //Set to false if you do not want this file to log. Useful in environments
23676 //like node where you want the work to happen without noise.
23679 convertDir: function (commonJsPath, savePath) {
23681 jsFileRegExp = /\.js$/,
23682 fileName, convertedFileName, fileContents;
23684 //Get list of files to convert.
23685 fileList = file.getFilteredFileList(commonJsPath, /\w/, true);
23687 //Normalize on front slashes and make sure the paths do not end in a slash.
23688 commonJsPath = commonJsPath.replace(/\\/g, "/");
23689 savePath = savePath.replace(/\\/g, "/");
23690 if (commonJsPath.charAt(commonJsPath.length - 1) === "/") {
23691 commonJsPath = commonJsPath.substring(0, commonJsPath.length - 1);
23693 if (savePath.charAt(savePath.length - 1) === "/") {
23694 savePath = savePath.substring(0, savePath.length - 1);
23697 //Cycle through all the JS files and convert them.
23698 if (!fileList || !fileList.length) {
23699 if (commonJs.useLog) {
23700 if (commonJsPath === "convert") {
23701 //A request just to convert one file.
23702 console.log('\n\n' + commonJs.convert(savePath, file.readFile(savePath)));
23704 console.log("No files to convert in directory: " + commonJsPath);
23708 for (i = 0; i < fileList.length; i++) {
23709 fileName = fileList[i];
23710 convertedFileName = fileName.replace(commonJsPath, savePath);
23713 if (jsFileRegExp.test(fileName)) {
23714 fileContents = file.readFile(fileName);
23715 fileContents = commonJs.convert(fileName, fileContents);
23716 file.saveUtf8File(convertedFileName, fileContents);
23718 //Just copy the file over.
23719 file.copyFile(fileName, convertedFileName, true);
23726 * Does the actual file conversion.
23728 * @param {String} fileName the name of the file.
23730 * @param {String} fileContents the contents of a file :)
23732 * @returns {String} the converted contents
23734 convert: function (fileName, fileContents) {
23735 //Strip out comments.
23738 commonJsProps = parse.usesCommonJs(fileName, fileContents);
23740 //First see if the module is not already RequireJS-formatted.
23741 if (parse.usesAmdOrRequireJs(fileName, fileContents) || !commonJsProps) {
23742 return fileContents;
23745 if (commonJsProps.dirname || commonJsProps.filename) {
23746 preamble = 'var __filename = module.uri || "", ' +
23747 '__dirname = __filename.substring(0, __filename.lastIndexOf("/") + 1); ';
23750 //Construct the wrapper boilerplate.
23751 fileContents = 'define(function (require, exports, module) {' +
23757 console.log("commonJs.convert: COULD NOT CONVERT: " + fileName + ", so skipping it. Error was: " + e);
23758 return fileContents;
23761 return fileContents;
23768 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
23769 * Available via the MIT or new BSD license.
23770 * see: http://github.com/jrburke/requirejs for details
23773 /*jslint plusplus: true, nomen: true, regexp: true */
23774 /*global define, requirejs */
23777 define('build', function (require) {
23780 var build, buildBaseConfig,
23781 lang = require('lang'),
23782 prim = require('prim'),
23783 logger = require('logger'),
23784 file = require('env!env/file'),
23785 parse = require('parse'),
23786 optimize = require('optimize'),
23787 pragma = require('pragma'),
23788 transform = require('transform'),
23789 requirePatch = require('requirePatch'),
23790 env = require('env'),
23791 commonJs = require('commonJs'),
23792 SourceMapGenerator = require('source-map/source-map-generator'),
23793 hasProp = lang.hasProp,
23794 getOwn = lang.getOwn,
23795 falseProp = lang.falseProp,
23796 endsWithSemiColonRegExp = /;\s*$/;
23798 prim.nextTick = function (fn) {
23802 //Now map require to the outermost requirejs, now that we have
23803 //local dependencies for this module. The rest of the require use is
23804 //manipulating the requirejs loader.
23805 require = requirejs;
23807 //Caching function for performance. Attached to
23808 //require so it can be reused in requirePatch.js. _cachedRawText
23809 //set up by requirePatch.js
23810 require._cacheReadAsync = function (path, encoding) {
23813 if (lang.hasProp(require._cachedRawText, path)) {
23815 d.resolve(require._cachedRawText[path]);
23818 return file.readFileAsync(path, encoding).then(function (text) {
23819 require._cachedRawText[path] = text;
23825 buildBaseConfig = {
23829 optimize: "uglify",
23830 optimizeCss: "standard.keepLines",
23833 optimizeAllPluginResources: false,
23834 findNestedDependencies: false,
23835 preserveLicenseComments: true,
23836 //By default, all files/directories are copied, unless
23837 //they match this regexp, by default just excludes .folders
23838 dirExclusionRegExp: file.dirExclusionRegExp,
23839 _buildPathToModuleIndex: {}
23843 * Some JS may not be valid if concatenated with other JS, in particular
23844 * the style of omitting semicolons and rely on ASI. Add a semicolon in
23847 function addSemiColon(text, config) {
23848 if (config.skipSemiColonInsertion || endsWithSemiColonRegExp.test(text)) {
23855 function endsWithSlash(dirName) {
23856 if (dirName.charAt(dirName.length - 1) !== "/") {
23862 //Method used by plugin writeFile calls, defined up here to avoid
23863 //jslint warning about "making a function in a loop".
23864 function makeWriteFile(namespace, layer) {
23865 function writeFile(name, contents) {
23866 logger.trace('Saving plugin-optimized file: ' + name);
23867 file.saveUtf8File(name, contents);
23870 writeFile.asModule = function (moduleName, fileName, contents) {
23871 writeFile(fileName,
23872 build.toTransport(namespace, moduleName, fileName, contents, layer));
23879 * Main API entry point into the build. The args argument can either be
23880 * an array of arguments (like the onese passed on a command-line),
23881 * or it can be a JavaScript object that has the format of a build profile
23884 * If it is an object, then in addition to the normal properties allowed in
23885 * a build profile file, the object should contain one other property:
23887 * The object could also contain a "buildFile" property, which is a string
23888 * that is the file path to a build profile that contains the rest
23889 * of the build profile directives.
23891 * This function does not return a status, it should throw an error if
23892 * there is a problem completing the build.
23894 build = function (args) {
23895 var buildFile, cmdConfig, errorMsg, errorStack, stackMatch, errorTree,
23897 stackRegExp = /( {4}at[^\n]+)\n/,
23898 standardIndent = ' ';
23900 return prim().start(function () {
23901 if (!args || lang.isArray(args)) {
23902 if (!args || args.length < 1) {
23903 logger.error("build.js buildProfile.js\n" +
23904 "where buildProfile.js is the name of the build file (see example.build.js for hints on how to make a build file).");
23908 //Next args can include a build file path as well as other build args.
23909 //build file path comes first. If it does not contain an = then it is
23910 //a build file path. Otherwise, just all build args.
23911 if (args[0].indexOf("=") === -1) {
23912 buildFile = args[0];
23916 //Remaining args are options to the build
23917 cmdConfig = build.convertArrayToObject(args);
23918 cmdConfig.buildFile = buildFile;
23923 return build._run(cmdConfig);
23924 }).then(null, function (e) {
23925 errorMsg = e.toString();
23926 errorTree = e.moduleTree;
23927 stackMatch = stackRegExp.exec(errorMsg);
23930 errorMsg += errorMsg.substring(0, stackMatch.index + stackMatch[0].length + 1);
23933 //If a module tree that shows what module triggered the error,
23935 if (errorTree && errorTree.length > 0) {
23936 errorMsg += '\nIn module tree:\n';
23938 for (i = errorTree.length - 1; i > -1; i--) {
23939 errorMod = errorTree[i];
23941 for (j = errorTree.length - i; j > -1; j--) {
23942 errorMsg += standardIndent;
23944 errorMsg += errorMod + '\n';
23948 logger.error(errorMsg);
23951 errorStack = e.stack;
23953 if (typeof args === 'string' && args.indexOf('stacktrace=true') !== -1) {
23954 errorMsg += '\n' + errorStack;
23956 if (!stackMatch && errorStack) {
23957 //Just trim out the first "at" in the stack.
23958 stackMatch = stackRegExp.exec(errorStack);
23960 errorMsg += '\n' + stackMatch[0] || '';
23965 throw new Error(errorMsg);
23969 build._run = function (cmdConfig) {
23970 var buildPaths, fileName, fileNames,
23972 baseConfig, config,
23973 modules, srcPath, buildContext,
23974 destPath, moduleMap, parentModuleMap, context,
23975 resources, resource, plugin, fileContents,
23976 pluginProcessed = {},
23977 buildFileContents = "",
23978 pluginCollector = {};
23980 return prim().start(function () {
23983 //Can now run the patches to require.js to allow it to be used for
23984 //build generation. Do it here instead of at the top of the module
23985 //because we want normal require behavior to load the build tool
23986 //then want to switch to build mode.
23989 config = build.createConfig(cmdConfig);
23990 paths = config.paths;
23992 //Remove the previous build dir, in case it contains source transforms,
23993 //like the ones done with onBuildRead and onBuildWrite.
23994 if (config.dir && !config.keepBuildDir && file.exists(config.dir)) {
23995 file.deleteFile(config.dir);
23998 if (!config.out && !config.cssIn) {
23999 //This is not just a one-off file build but a full build profile, with
24000 //lots of files to process.
24002 //First copy all the baseUrl content
24003 file.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true);
24005 //Adjust baseUrl if config.appDir is in play, and set up build output paths.
24007 if (config.appDir) {
24008 //All the paths should be inside the appDir, so just adjust
24009 //the paths to use the dirBaseUrl
24010 for (prop in paths) {
24011 if (hasProp(paths, prop)) {
24012 buildPaths[prop] = paths[prop].replace(config.appDir, config.dir);
24016 //If no appDir, then make sure to copy the other paths to this directory.
24017 for (prop in paths) {
24018 if (hasProp(paths, prop)) {
24019 //Set up build path for each path prefix, but only do so
24020 //if the path falls out of the current baseUrl
24021 if (paths[prop].indexOf(config.baseUrl) === 0) {
24022 buildPaths[prop] = paths[prop].replace(config.baseUrl, config.dirBaseUrl);
24024 buildPaths[prop] = paths[prop] === 'empty:' ? 'empty:' : prop.replace(/\./g, "/");
24026 //Make sure source path is fully formed with baseUrl,
24027 //if it is a relative URL.
24028 srcPath = paths[prop];
24029 if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) {
24030 srcPath = config.baseUrl + srcPath;
24033 destPath = config.dirBaseUrl + buildPaths[prop];
24035 //Skip empty: paths
24036 if (srcPath !== 'empty:') {
24037 //If the srcPath is a directory, copy the whole directory.
24038 if (file.exists(srcPath) && file.isDirectory(srcPath)) {
24039 //Copy files to build area. Copy all files (the /\w/ regexp)
24040 file.copyDir(srcPath, destPath, /\w/, true);
24042 //Try a .js extension
24045 file.copyFile(srcPath, destPath);
24054 //Figure out source file location for each module layer. Do this by seeding require
24055 //with source area configuration. This is needed so that later the module layers
24056 //can be manually copied over to the source area, since the build may be
24057 //require multiple times and the above copyDir call only copies newer files.
24059 baseUrl: config.baseUrl,
24061 packagePaths: config.packagePaths,
24062 packages: config.packages
24064 buildContext = require.s.contexts._;
24065 modules = config.modules;
24068 modules.forEach(function (module) {
24070 module._sourcePath = buildContext.nameToUrl(module.name);
24071 //If the module does not exist, and this is not a "new" module layer,
24072 //as indicated by a true "create" property on the module, and
24073 //it is not a plugin-loaded resource, and there is no
24074 //'rawText' containing the module's source then throw an error.
24075 if (!file.exists(module._sourcePath) && !module.create &&
24076 module.name.indexOf('!') === -1 &&
24077 (!config.rawText || !lang.hasProp(config.rawText, module.name))) {
24078 throw new Error("ERROR: module path does not exist: " +
24079 module._sourcePath + " for module named: " + module.name +
24080 ". Path is relative to: " + file.absPath('.'));
24087 //Just set up the _buildPath for the module layer.
24089 if (!config.cssIn) {
24090 config.modules[0]._buildPath = typeof config.out === 'function' ?
24091 'FUNCTION' : config.out;
24093 } else if (!config.cssIn) {
24094 //Now set up the config for require to use the build area, and calculate the
24095 //build file locations. Pass along any config info too.
24097 baseUrl: config.dirBaseUrl,
24101 lang.mixin(baseConfig, config);
24102 require(baseConfig);
24105 modules.forEach(function (module) {
24107 module._buildPath = buildContext.nameToUrl(module.name, null);
24108 if (!module.create) {
24109 file.copyFile(module._sourcePath, module._buildPath);
24116 //Run CSS optimizations before doing JS module tracing, to allow
24117 //things like text loader plugins loading CSS to get the optimized
24119 if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) {
24120 buildFileContents += optimize.css(config.dir, config);
24122 }).then(function () {
24126 actions = modules.map(function (module, i) {
24127 return function () {
24128 //Save off buildPath to module index in a hash for quicker
24130 config._buildPathToModuleIndex[module._buildPath] = i;
24132 //Call require to calculate dependencies.
24133 return build.traceDependencies(module, config)
24134 .then(function (layer) {
24135 module.layer = layer;
24140 return prim.serial(actions);
24142 }).then(function () {
24146 //Now build up shadow layers for anything that should be excluded.
24147 //Do this after tracing dependencies for each module, in case one
24148 //of those modules end up being one of the excluded values.
24149 actions = modules.map(function (module) {
24150 return function () {
24151 if (module.exclude) {
24152 module.excludeLayers = [];
24153 return prim.serial(module.exclude.map(function (exclude, i) {
24154 return function () {
24155 //See if it is already in the list of modules.
24156 //If not trace dependencies for it.
24157 var found = build.findBuildModule(exclude, modules);
24159 module.excludeLayers[i] = found;
24161 return build.traceDependencies({name: exclude}, config)
24162 .then(function (layer) {
24163 module.excludeLayers[i] = { layer: layer };
24172 return prim.serial(actions);
24174 }).then(function () {
24176 return prim.serial(modules.map(function (module) {
24177 return function () {
24178 if (module.exclude) {
24179 //module.exclude is an array of module names. For each one,
24180 //get the nested dependencies for it via a matching entry
24181 //in the module.excludeLayers array.
24182 module.exclude.forEach(function (excludeModule, i) {
24183 var excludeLayer = module.excludeLayers[i].layer,
24184 map = excludeLayer.buildFileToModule;
24185 excludeLayer.buildFilePaths.forEach(function(filePath){
24186 build.removeModulePath(map[filePath], filePath, module.layer);
24190 if (module.excludeShallow) {
24191 //module.excludeShallow is an array of module names.
24192 //shallow exclusions are just that module itself, and not
24193 //its nested dependencies.
24194 module.excludeShallow.forEach(function (excludeShallowModule) {
24195 var path = getOwn(module.layer.buildPathMap, excludeShallowModule);
24197 build.removeModulePath(excludeShallowModule, path, module.layer);
24202 //Flatten them and collect the build output for each module.
24203 return build.flattenModule(module, module.layer, config).then(function (builtModule) {
24204 var finalText, baseName;
24205 //Save it to a temp file for now, in case there are other layers that
24206 //contain optimized content that should not be included in later
24207 //layer optimizations. See issue #56.
24208 if (module._buildPath === 'FUNCTION') {
24209 module._buildText = builtModule.text;
24210 module._buildSourceMap = builtModule.sourceMap;
24212 finalText = builtModule.text;
24213 if (builtModule.sourceMap) {
24214 baseName = module._buildPath.split('/');
24215 baseName = baseName.pop();
24216 finalText += '\n//# sourceMappingURL=' + baseName + '.map';
24217 file.saveUtf8File(module._buildPath + '.map', builtModule.sourceMap);
24219 file.saveUtf8File(module._buildPath + '-temp', finalText);
24222 buildFileContents += builtModule.buildText;
24227 }).then(function () {
24230 //Now move the build layers to their final position.
24231 modules.forEach(function (module) {
24232 var finalPath = module._buildPath;
24233 if (finalPath !== 'FUNCTION') {
24234 if (file.exists(finalPath)) {
24235 file.deleteFile(finalPath);
24237 file.renameFile(finalPath + '-temp', finalPath);
24239 //And finally, if removeCombined is specified, remove
24240 //any of the files that were used in this layer.
24241 //Be sure not to remove other build layers.
24242 if (config.removeCombined) {
24243 module.layer.buildFilePaths.forEach(function (path) {
24244 if (file.exists(path) && !modules.some(function (mod) {
24245 return mod._buildPath === path;
24247 file.deleteFile(path);
24253 //Signal layer is done
24254 if (config.onModuleBundleComplete) {
24255 config.onModuleBundleComplete(module.onCompleteData);
24260 //If removeCombined in play, remove any empty directories that
24261 //may now exist because of its use
24262 if (config.removeCombined && !config.out && config.dir) {
24263 file.deleteEmptyDirs(config.dir);
24266 //Do other optimizations.
24267 if (config.out && !config.cssIn) {
24268 //Just need to worry about one JS file.
24269 fileName = config.modules[0]._buildPath;
24270 if (fileName === 'FUNCTION') {
24271 config.modules[0]._buildText = optimize.js(fileName,
24272 config.modules[0]._buildText,
24276 optimize.jsFile(fileName, null, fileName, config);
24278 } else if (!config.cssIn) {
24279 //Normal optimizations across modules.
24281 //JS optimizations.
24282 fileNames = file.getFilteredFileList(config.dir, /\.js$/, true);
24283 fileNames.forEach(function (fileName) {
24284 var cfg, override, moduleIndex;
24286 //Generate the module name from the config.dir root.
24287 moduleName = fileName.replace(config.dir, '');
24288 //Get rid of the extension
24289 moduleName = moduleName.substring(0, moduleName.length - 3);
24291 //If there is an override for a specific layer build module,
24292 //and this file is that module, mix in the override for use
24293 //by optimize.jsFile.
24294 moduleIndex = getOwn(config._buildPathToModuleIndex, fileName);
24295 //Normalize, since getOwn could have returned undefined
24296 moduleIndex = moduleIndex === 0 || moduleIndex > 0 ? moduleIndex : -1;
24298 //Try to avoid extra work if the other files do not need to
24299 //be read. Build layers should be processed at the very
24300 //least for optimization.
24301 if (moduleIndex > -1 || !config.skipDirOptimize ||
24302 config.normalizeDirDefines === "all" ||
24303 config.cjsTranslate) {
24304 //Convert the file to transport format, but without a name
24305 //inserted (by passing null for moduleName) since the files are
24306 //standalone, one module per file.
24307 fileContents = file.readFile(fileName);
24310 //For builds, if wanting cjs translation, do it now, so that
24311 //the individual modules can be loaded cross domain via
24312 //plain script tags.
24313 if (config.cjsTranslate &&
24314 (!config.shim || !lang.hasProp(config.shim, moduleName))) {
24315 fileContents = commonJs.convert(fileName, fileContents);
24318 if (moduleIndex === -1) {
24319 if (config.onBuildRead) {
24320 fileContents = config.onBuildRead(moduleName,
24325 //Only do transport normalization if this is not a build
24326 //layer (since it was already normalized) and if
24327 //normalizeDirDefines indicated all should be done.
24328 if (config.normalizeDirDefines === "all") {
24329 fileContents = build.toTransport(config.namespace,
24335 if (config.onBuildWrite) {
24336 fileContents = config.onBuildWrite(moduleName,
24342 override = moduleIndex > -1 ?
24343 config.modules[moduleIndex].override : null;
24345 cfg = build.createOverrideConfig(config, override);
24350 if (moduleIndex > -1 || !config.skipDirOptimize) {
24351 optimize.jsFile(fileName, fileContents, fileName, cfg, pluginCollector);
24356 //Normalize all the plugin resources.
24357 context = require.s.contexts._;
24359 for (moduleName in pluginCollector) {
24360 if (hasProp(pluginCollector, moduleName)) {
24361 parentModuleMap = context.makeModuleMap(moduleName);
24362 resources = pluginCollector[moduleName];
24363 for (i = 0; i < resources.length; i++) {
24364 resource = resources[i];
24365 moduleMap = context.makeModuleMap(resource, parentModuleMap);
24366 if (falseProp(context.plugins, moduleMap.prefix)) {
24367 //Set the value in context.plugins so it
24368 //will be evaluated as a full plugin.
24369 context.plugins[moduleMap.prefix] = true;
24371 //Do not bother if the plugin is not available.
24372 if (!file.exists(require.toUrl(moduleMap.prefix + '.js'))) {
24376 //Rely on the require in the build environment
24377 //to be synchronous
24378 context.require([moduleMap.prefix]);
24380 //Now that the plugin is loaded, redo the moduleMap
24381 //since the plugin will need to normalize part of the path.
24382 moduleMap = context.makeModuleMap(resource, parentModuleMap);
24385 //Only bother with plugin resources that can be handled
24386 //processed by the plugin, via support of the writeFile
24388 if (falseProp(pluginProcessed, moduleMap.id)) {
24389 //Only do the work if the plugin was really loaded.
24390 //Using an internal access because the file may
24391 //not really be loaded.
24392 plugin = getOwn(context.defined, moduleMap.prefix);
24393 if (plugin && plugin.writeFile) {
24405 pluginProcessed[moduleMap.id] = true;
24412 //console.log('PLUGIN COLLECTOR: ' + JSON.stringify(pluginCollector, null, " "));
24415 //All module layers are done, write out the build.txt file.
24416 file.saveUtf8File(config.dir + "build.txt", buildFileContents);
24419 //If just have one CSS file to optimize, do that here.
24420 if (config.cssIn) {
24421 buildFileContents += optimize.cssFile(config.cssIn, config.out, config).buildText;
24424 if (typeof config.out === 'function') {
24425 config.out(config.modules[0]._buildText);
24428 //Print out what was built into which layers.
24429 if (buildFileContents) {
24430 logger.info(buildFileContents);
24431 return buildFileContents;
24439 * Converts command line args like "paths.foo=../some/path"
24440 * result.paths = { foo: '../some/path' } where prop = paths,
24441 * name = paths.foo and value = ../some/path, so it assumes the
24442 * name=value splitting has already happened.
24444 function stringDotToObj(result, name, value) {
24445 var parts = name.split('.');
24447 parts.forEach(function (prop, i) {
24448 if (i === parts.length - 1) {
24449 result[prop] = value;
24451 if (falseProp(result, prop)) {
24454 result = result[prop];
24464 pragmasOnSave: true,
24474 build.hasDotPropMatch = function (prop) {
24476 index = prop.indexOf('.');
24478 if (index !== -1) {
24479 dotProp = prop.substring(0, index);
24480 return hasProp(build.objProps, dotProp);
24486 * Converts an array that has String members of "name=value"
24487 * into an object, where the properties on the object are the names in the array.
24488 * Also converts the strings "true" and "false" to booleans for the values.
24489 * member name/value pairs, and converts some comma-separated lists into
24491 * @param {Array} ary
24493 build.convertArrayToObject = function (ary) {
24494 var result = {}, i, separatorIndex, prop, value,
24498 "excludeShallow": true,
24499 "insertRequire": true,
24500 "stubModules": true,
24504 for (i = 0; i < ary.length; i++) {
24505 separatorIndex = ary[i].indexOf("=");
24506 if (separatorIndex === -1) {
24507 throw "Malformed name/value pair: [" + ary[i] + "]. Format should be name=value";
24510 value = ary[i].substring(separatorIndex + 1, ary[i].length);
24511 if (value === "true") {
24513 } else if (value === "false") {
24517 prop = ary[i].substring(0, separatorIndex);
24519 //Convert to array if necessary
24520 if (getOwn(needArray, prop)) {
24521 value = value.split(",");
24524 if (build.hasDotPropMatch(prop)) {
24525 stringDotToObj(result, prop, value);
24527 result[prop] = value;
24530 return result; //Object
24533 build.makeAbsPath = function (path, absFilePath) {
24534 if (!absFilePath) {
24538 //Add abspath if necessary. If path starts with a slash or has a colon,
24539 //then already is an abolute path.
24540 if (path.indexOf('/') !== 0 && path.indexOf(':') === -1) {
24541 path = absFilePath +
24542 (absFilePath.charAt(absFilePath.length - 1) === '/' ? '' : '/') +
24544 path = file.normalize(path);
24546 return path.replace(lang.backSlashRegExp, '/');
24549 build.makeAbsObject = function (props, obj, absFilePath) {
24552 for (i = 0; i < props.length; i++) {
24554 if (hasProp(obj, prop) && typeof obj[prop] === 'string') {
24555 obj[prop] = build.makeAbsPath(obj[prop], absFilePath);
24562 * For any path in a possible config, make it absolute relative
24563 * to the absFilePath passed in.
24565 build.makeAbsConfig = function (config, absFilePath) {
24566 var props, prop, i;
24568 props = ["appDir", "dir", "baseUrl"];
24569 for (i = 0; i < props.length; i++) {
24572 if (getOwn(config, prop)) {
24573 //Add abspath if necessary, make sure these paths end in
24575 if (prop === "baseUrl") {
24576 config.originalBaseUrl = config.baseUrl;
24577 if (config.appDir) {
24578 //If baseUrl with an appDir, the baseUrl is relative to
24579 //the appDir, *not* the absFilePath. appDir and dir are
24580 //made absolute before baseUrl, so this will work.
24581 config.baseUrl = build.makeAbsPath(config.originalBaseUrl, config.appDir);
24583 //The dir output baseUrl is same as regular baseUrl, both
24584 //relative to the absFilePath.
24585 config.baseUrl = build.makeAbsPath(config[prop], absFilePath);
24588 config[prop] = build.makeAbsPath(config[prop], absFilePath);
24591 config[prop] = endsWithSlash(config[prop]);
24595 build.makeAbsObject(["out", "cssIn"], config, absFilePath);
24596 build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath);
24600 * Creates a relative path to targetPath from refPath.
24601 * Only deals with file paths, not folders. If folders,
24602 * make sure paths end in a trailing '/'.
24604 build.makeRelativeFilePath = function (refPath, targetPath) {
24605 var i, dotLength, finalParts, length,
24606 refParts = refPath.split('/'),
24607 targetParts = targetPath.split('/'),
24608 //Pull off file name
24609 targetName = targetParts.pop(),
24612 //Also pop off the ref file name to make the matches against
24613 //targetParts equivalent.
24616 length = refParts.length;
24618 for (i = 0; i < length; i += 1) {
24619 if (refParts[i] !== targetParts[i]) {
24624 //Now i is the index in which they diverge.
24625 finalParts = targetParts.slice(i);
24627 dotLength = length - i;
24628 for (i = 0; i > -1 && i < dotLength; i += 1) {
24629 dotParts.push('..');
24632 return dotParts.join('/') + (dotParts.length ? '/' : '') +
24633 finalParts.join('/') + (finalParts.length ? '/' : '') +
24637 build.nestedMix = {
24642 pragmasOnSave: true
24646 * Mixes additional source config into target config, and merges some
24647 * nested config, like paths, correctly.
24649 function mixConfig(target, source) {
24652 for (prop in source) {
24653 if (hasProp(source, prop)) {
24654 //If the value of the property is a plain object, then
24655 //allow a one-level-deep mixing of it.
24656 value = source[prop];
24657 if (typeof value === 'object' && value &&
24658 !lang.isArray(value) && !lang.isFunction(value) &&
24659 !lang.isRegExp(value)) {
24660 target[prop] = lang.mixin({}, target[prop], value, true);
24662 target[prop] = value;
24667 //Set up log level since it can affect if errors are thrown
24668 //or caught and passed to errbacks while doing config setup.
24669 if (lang.hasProp(target, 'logLevel')) {
24670 logger.logLevel(target.logLevel);
24675 * Converts a wrap.startFile or endFile to be start/end as a string.
24676 * the startFile/endFile values can be arrays.
24678 function flattenWrapFile(wrap, keyName, absFilePath) {
24679 var keyFileName = keyName + 'File';
24681 if (typeof wrap[keyName] !== 'string' && wrap[keyFileName]) {
24682 wrap[keyName] = '';
24683 if (typeof wrap[keyFileName] === 'string') {
24684 wrap[keyFileName] = [wrap[keyFileName]];
24686 wrap[keyFileName].forEach(function (fileName) {
24687 wrap[keyName] += (wrap[keyName] ? '\n' : '') +
24688 file.readFile(build.makeAbsPath(fileName, absFilePath));
24690 } else if (wrap[keyName] === null || wrap[keyName] === undefined) {
24691 //Allow missing one, just set to empty string.
24692 wrap[keyName] = '';
24693 } else if (typeof wrap[keyName] !== 'string') {
24694 throw new Error('wrap.' + keyName + ' or wrap.' + keyFileName + ' malformed');
24699 * Creates a config object for an optimization build.
24700 * It will also read the build profile if it is available, to create
24701 * the configuration.
24703 * @param {Object} cfg config options that take priority
24704 * over defaults and ones in the build file. These options could
24705 * be from a command line, for instance.
24707 * @param {Object} the created config object.
24709 build.createConfig = function (cfg) {
24710 /*jslint evil: true */
24711 var config = {}, buildFileContents, buildFileConfig, mainConfig,
24712 mainConfigFile, mainConfigPath, buildFile, absFilePath;
24714 //Make sure all paths are relative to current directory.
24715 absFilePath = file.absPath('.');
24716 build.makeAbsConfig(cfg, absFilePath);
24717 build.makeAbsConfig(buildBaseConfig, absFilePath);
24719 lang.mixin(config, buildBaseConfig);
24720 lang.mixin(config, cfg, true);
24722 //Set up log level early since it can affect if errors are thrown
24723 //or caught and passed to errbacks, even while constructing config.
24724 if (lang.hasProp(config, 'logLevel')) {
24725 logger.logLevel(config.logLevel);
24728 if (config.buildFile) {
24729 //A build file exists, load it to get more config.
24730 buildFile = file.absPath(config.buildFile);
24732 //Find the build file, and make sure it exists, if this is a build
24733 //that has a build profile, and not just command line args with an in=path
24734 if (!file.exists(buildFile)) {
24735 throw new Error("ERROR: build file does not exist: " + buildFile);
24738 absFilePath = config.baseUrl = file.absPath(file.parent(buildFile));
24740 //Load build file options.
24741 buildFileContents = file.readFile(buildFile);
24743 buildFileConfig = eval("(" + buildFileContents + ")");
24744 build.makeAbsConfig(buildFileConfig, absFilePath);
24746 //Mix in the config now so that items in mainConfigFile can
24747 //be resolved relative to them if necessary, like if appDir
24748 //is set here, but the baseUrl is in mainConfigFile. Will
24749 //re-mix in the same build config later after mainConfigFile
24750 //is processed, since build config should take priority.
24751 mixConfig(config, buildFileConfig);
24753 throw new Error("Build file " + buildFile + " is malformed: " + e);
24757 mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile);
24758 if (mainConfigFile) {
24759 mainConfigFile = build.makeAbsPath(mainConfigFile, absFilePath);
24760 if (!file.exists(mainConfigFile)) {
24761 throw new Error(mainConfigFile + ' does not exist.');
24764 mainConfig = parse.findConfig(file.readFile(mainConfigFile)).config;
24765 } catch (configError) {
24766 throw new Error('The config in mainConfigFile ' +
24768 ' cannot be used because it cannot be evaluated' +
24769 ' correctly while running in the optimizer. Try only' +
24770 ' using a config that is also valid JSON, or do not use' +
24771 ' mainConfigFile and instead copy the config values needed' +
24772 ' into a build file or command line arguments given to the optimizer.\n' +
24773 'Source error from parsing: ' + mainConfigFile + ': ' + configError);
24776 mainConfigPath = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/'));
24778 //Add in some existing config, like appDir, since they can be
24779 //used inside the mainConfigFile -- paths and baseUrl are
24780 //relative to them.
24781 if (config.appDir && !mainConfig.appDir) {
24782 mainConfig.appDir = config.appDir;
24785 //If no baseUrl, then use the directory holding the main config.
24786 if (!mainConfig.baseUrl) {
24787 mainConfig.baseUrl = mainConfigPath;
24790 build.makeAbsConfig(mainConfig, mainConfigPath);
24791 mixConfig(config, mainConfig);
24795 //Mix in build file config, but only after mainConfig has been mixed in.
24796 if (buildFileConfig) {
24797 mixConfig(config, buildFileConfig);
24800 //Re-apply the override config values. Command line
24801 //args should take precedence over build file values.
24802 mixConfig(config, cfg);
24804 //Fix paths to full paths so that they can be adjusted consistently
24805 //lately to be in the output area.
24806 lang.eachProp(config.paths, function (value, prop) {
24807 if (lang.isArray(value)) {
24808 throw new Error('paths fallback not supported in optimizer. ' +
24809 'Please provide a build config path override ' +
24812 config.paths[prop] = build.makeAbsPath(value, config.baseUrl);
24815 //Set final output dir
24816 if (hasProp(config, "baseUrl")) {
24817 if (config.appDir) {
24818 config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir);
24820 config.dirBaseUrl = config.dir || config.baseUrl;
24822 //Make sure dirBaseUrl ends in a slash, since it is
24823 //concatenated with other strings.
24824 config.dirBaseUrl = endsWithSlash(config.dirBaseUrl);
24827 //Check for errors in config
24829 throw new Error('"main" passed as an option, but the ' +
24830 'supported option is called "name".');
24832 if (config.out && !config.name && !config.modules && !config.include &&
24834 throw new Error('Missing either a "name", "include" or "modules" ' +
24837 if (config.cssIn) {
24838 if (config.dir || config.appDir) {
24839 throw new Error('cssIn is only for the output of single file ' +
24840 'CSS optimizations and is not compatible with "dir" or "appDir" configuration.');
24843 throw new Error('"out" option missing.');
24846 if (!config.cssIn && !config.baseUrl) {
24847 //Just use the current directory as the baseUrl
24848 config.baseUrl = './';
24850 if (!config.out && !config.dir) {
24851 throw new Error('Missing either an "out" or "dir" config value. ' +
24852 'If using "appDir" for a full project optimization, ' +
24853 'use "dir". If you want to optimize to one file, ' +
24856 if (config.appDir && config.out) {
24857 throw new Error('"appDir" is not compatible with "out". Use "dir" ' +
24858 'instead. appDir is used to copy whole projects, ' +
24859 'where "out" with "baseUrl" is used to just ' +
24860 'optimize to one file.');
24862 if (config.out && config.dir) {
24863 throw new Error('The "out" and "dir" options are incompatible.' +
24864 ' Use "out" if you are targeting a single file for' +
24865 ' for optimization, and "dir" if you want the appDir' +
24866 ' or baseUrl directories optimized.');
24870 // Make sure the output dir is not set to a parent of the
24871 // source dir or the same dir, as it will result in source
24873 if (config.dir === config.baseUrl ||
24874 config.dir === config.appDir ||
24875 (config.baseUrl && build.makeRelativeFilePath(config.dir,
24876 config.baseUrl).indexOf('..') !== 0) ||
24878 build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0)) {
24879 throw new Error('"dir" is set to a parent or same directory as' +
24880 ' "appDir" or "baseUrl". This can result in' +
24881 ' the deletion of source code. Stopping.');
24885 if (config.insertRequire && !lang.isArray(config.insertRequire)) {
24886 throw new Error('insertRequire should be a list of module IDs' +
24887 ' to insert in to a require([]) call.');
24890 if (config.generateSourceMaps) {
24891 if (config.preserveLicenseComments && config.optimize !== 'none') {
24892 throw new Error('Cannot use preserveLicenseComments and ' +
24893 'generateSourceMaps together. Either explcitly set ' +
24894 'preserveLicenseComments to false (default is true) or ' +
24895 'turn off generateSourceMaps. If you want source maps with ' +
24896 'license comments, see: ' +
24897 'http://requirejs.org/docs/errors.html#sourcemapcomments');
24898 } else if (config.optimize !== 'none' &&
24899 config.optimize !== 'closure' &&
24900 config.optimize !== 'uglify2') {
24901 //Allow optimize: none to pass, since it is useful when toggling
24902 //minification on and off to debug something, and it implicitly
24903 //works, since it does not need a source map.
24904 throw new Error('optimize: "' + config.optimize +
24905 '" does not support generateSourceMaps.');
24909 if ((config.name || config.include) && !config.modules) {
24910 //Just need to build one file, but may be part of a whole appDir/
24911 //baseUrl copy, but specified on the command line, so cannot do
24912 //the modules array setup. So create a modules section in that
24918 create: config.create,
24919 include: config.include,
24920 exclude: config.exclude,
24921 excludeShallow: config.excludeShallow,
24922 insertRequire: config.insertRequire,
24923 stubModules: config.stubModules
24926 delete config.stubModules;
24927 } else if (config.modules && config.out) {
24928 throw new Error('If the "modules" option is used, then there ' +
24929 'should be a "dir" option set and "out" should ' +
24930 'not be used since "out" is only for single file ' +
24931 'optimization output.');
24932 } else if (config.modules && config.name) {
24933 throw new Error('"name" and "modules" options are incompatible. ' +
24934 'Either use "name" if doing a single file ' +
24935 'optimization, or "modules" if you want to target ' +
24936 'more than one file for optimization.');
24939 if (config.out && !config.cssIn) {
24940 //Just one file to optimize.
24942 //Does not have a build file, so set up some defaults.
24943 //Optimizing CSS should not be allowed, unless explicitly
24944 //asked for on command line. In that case the only task is
24945 //to optimize a CSS file.
24946 if (!cfg.optimizeCss) {
24947 config.optimizeCss = "none";
24951 //Normalize cssPrefix
24952 if (config.cssPrefix) {
24953 //Make sure cssPrefix ends in a slash
24954 config.cssPrefix = endsWithSlash(config.cssPrefix);
24956 config.cssPrefix = '';
24959 //Cycle through modules and combine any local stubModules with
24961 if (config.modules && config.modules.length) {
24962 config.modules.forEach(function (mod) {
24963 if (config.stubModules) {
24964 mod.stubModules = config.stubModules.concat(mod.stubModules || []);
24967 //Create a hash lookup for the stubModules config to make lookup
24969 if (mod.stubModules) {
24970 mod.stubModules._byName = {};
24971 mod.stubModules.forEach(function (id) {
24972 mod.stubModules._byName[id] = true;
24978 //Get any wrap text.
24981 if (config.wrap === true) {
24982 //Use default values.
24984 start: '(function () {',
24988 flattenWrapFile(config.wrap, 'start', absFilePath);
24989 flattenWrapFile(config.wrap, 'end', absFilePath);
24992 } catch (wrapError) {
24993 throw new Error('Malformed wrap config: ' + wrapError.toString());
24996 //Do final input verification
24997 if (config.context) {
24998 throw new Error('The build argument "context" is not supported' +
24999 ' in a build. It should only be used in web' +
25003 //Set up normalizeDirDefines. If not explicitly set, if optimize "none",
25004 //set to "skip" otherwise set to "all".
25005 if (!hasProp(config, 'normalizeDirDefines')) {
25006 if (config.optimize === 'none' || config.skipDirOptimize) {
25007 config.normalizeDirDefines = 'skip';
25009 config.normalizeDirDefines = 'all';
25013 //Set file.fileExclusionRegExp if desired
25014 if (hasProp(config, 'fileExclusionRegExp')) {
25015 if (typeof config.fileExclusionRegExp === "string") {
25016 file.exclusionRegExp = new RegExp(config.fileExclusionRegExp);
25018 file.exclusionRegExp = config.fileExclusionRegExp;
25020 } else if (hasProp(config, 'dirExclusionRegExp')) {
25021 //Set file.dirExclusionRegExp if desired, this is the old
25022 //name for fileExclusionRegExp before 1.0.2. Support for backwards
25024 file.exclusionRegExp = config.dirExclusionRegExp;
25027 //Remove things that may cause problems in the build.
25028 delete config.jQuery;
25029 delete config.enforceDefine;
25030 delete config.urlArgs;
25036 * finds the module being built/optimized with the given moduleName,
25038 * @param {String} moduleName
25039 * @param {Array} modules
25040 * @returns {Object} the module object from the build profile, or null.
25042 build.findBuildModule = function (moduleName, modules) {
25044 for (i = 0; i < modules.length; i++) {
25045 module = modules[i];
25046 if (module.name === moduleName) {
25054 * Removes a module name and path from a layer, if it is supposed to be
25055 * excluded from the layer.
25056 * @param {String} moduleName the name of the module
25057 * @param {String} path the file path for the module
25058 * @param {Object} layer the layer to remove the module/path from
25060 build.removeModulePath = function (module, path, layer) {
25061 var index = layer.buildFilePaths.indexOf(path);
25062 if (index !== -1) {
25063 layer.buildFilePaths.splice(index, 1);
25068 * Uses the module build config object to trace the dependencies for the
25071 * @param {Object} module the module object from the build config info.
25072 * @param {Object} the build config object.
25074 * @returns {Object} layer information about what paths and modules should
25075 * be in the flattened module.
25077 build.traceDependencies = function (module, config) {
25078 var include, override, layer, context, baseConfig, oldContext,
25087 //Reset some state set up in requirePatch.js, and clean up require's
25089 oldContext = require._buildReset();
25091 //Grab the reset layer and context after the reset, but keep the
25092 //old config to reuse in the new context.
25093 baseConfig = oldContext.config;
25094 layer = require._layer;
25095 context = layer.context;
25097 //Put back basic config, use a fresh object for it.
25098 //WARNING: probably not robust for paths and packages/packagePaths,
25099 //since those property's objects can be modified. But for basic
25100 //config clone it works out.
25101 require(lang.mixin({}, baseConfig, true));
25103 logger.trace("\nTracing dependencies for: " + (module.name || module.out));
25104 include = module.name && !module.create ? [module.name] : [];
25105 if (module.include) {
25106 include = include.concat(module.include);
25109 //If there are overrides to basic config, set that up now.;
25110 if (module.override) {
25111 override = lang.mixin({}, baseConfig, true);
25112 lang.mixin(override, module.override, true);
25116 //Now, populate the rawText cache with any values explicitly passed in
25118 rawTextByIds = require.s.contexts._.config.rawText;
25119 if (rawTextByIds) {
25120 lang.eachProp(rawTextByIds, function (contents, id) {
25121 var url = require.toUrl(id) + '.js';
25122 require._cachedRawText[url] = contents;
25127 //Configure the callbacks to be called.
25128 deferred.reject.__requireJsBuild = true;
25130 //Use a wrapping function so can check for errors.
25131 function includeFinished(value) {
25132 //If a sync build environment, check for errors here, instead of
25133 //in the then callback below, since some errors, like two IDs pointed
25134 //to same URL but only one anon ID will leave the loader in an
25135 //unresolved state since a setTimeout cannot be used to check for
25137 var hasError = false;
25138 if (syncChecks[env.get()]) {
25140 build.checkForErrors(context);
25143 deferred.reject(e);
25148 deferred.resolve(value);
25151 includeFinished.__requireJsBuild = true;
25153 //Figure out module layer dependencies by calling require to do the work.
25154 require(include, includeFinished, deferred.reject);
25156 return deferred.promise.then(function () {
25158 if (module.override) {
25159 require(baseConfig);
25162 build.checkForErrors(context);
25168 build.checkForErrors = function (context) {
25169 //Check to see if it all loaded. If not, then throw, and give
25170 //a message on what is left.
25171 var id, prop, mod, errUrl, idParts, pluginId,
25173 failedPluginMap = {},
25174 failedPluginIds = [],
25177 errUrlConflicts = {},
25179 registry = context.registry;
25181 for (id in registry) {
25182 if (hasProp(registry, id) && id.indexOf('_@r') !== 0) {
25183 mod = getOwn(registry, id);
25184 if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) {
25186 errUrl = mod.map.url;
25188 if (errUrlMap[errUrl]) {
25190 //This error module has the same URL as another
25191 //error module, could be misconfiguration.
25192 if (!errUrlConflicts[errUrl]) {
25193 errUrlConflicts[errUrl] = [];
25194 //Store the original module that had the same URL.
25195 errUrlConflicts[errUrl].push(errUrlMap[errUrl]);
25197 errUrlConflicts[errUrl].push(id);
25199 errUrlMap[errUrl] = id;
25203 //Look for plugins that did not call load()
25204 idParts = id.split('!');
25205 pluginId = idParts[0];
25206 if (idParts.length > 1 && falseProp(failedPluginMap, pluginId)) {
25207 failedPluginIds.push(pluginId);
25208 failedPluginMap[pluginId] = true;
25213 if (errIds.length || failedPluginIds.length) {
25214 if (failedPluginIds.length) {
25215 errMessage += 'Loader plugin' +
25216 (failedPluginIds.length === 1 ? '' : 's') +
25218 'the load callback in the build: ' +
25219 failedPluginIds.join(', ') + '\n';
25221 errMessage += 'Module loading did not complete for: ' + errIds.join(', ');
25224 errMessage += '\nThe following modules share the same URL. This ' +
25225 'could be a misconfiguration if that URL only has ' +
25226 'one anonymous module in it:';
25227 for (prop in errUrlConflicts) {
25228 if (hasProp(errUrlConflicts, prop)) {
25229 errMessage += '\n' + prop + ': ' +
25230 errUrlConflicts[prop].join(', ');
25234 throw new Error(errMessage);
25239 build.createOverrideConfig = function (config, override) {
25242 lang.mixin(cfg, config, true);
25243 lang.eachProp(override, function (value, prop) {
25244 if (hasProp(build.objProps, prop)) {
25245 //An object property, merge keys. Start a new object
25246 //so that source object in config does not get modified.
25248 lang.mixin(cfg[prop], config[prop], true);
25249 lang.mixin(cfg[prop], override[prop], true);
25251 cfg[prop] = override[prop];
25258 * Uses the module build config object to create an flattened version
25259 * of the module, with deep dependencies included.
25261 * @param {Object} module the module object from the build config info.
25263 * @param {Object} layer the layer object returned from build.traceDependencies.
25265 * @param {Object} the build config object.
25267 * @returns {Object} with two properties: "text", the text of the flattened
25268 * module, and "buildText", a string of text representing which files were
25269 * included in the flattened module text.
25271 build.flattenModule = function (module, layer, config) {
25272 var fileContents, sourceMapGenerator,
25274 buildFileContents = '';
25276 return prim().start(function () {
25277 var reqIndex, currContents,
25278 moduleName, shim, packageConfig, nonPackageName,
25279 parts, builder, writeApi,
25280 namespace, namespaceWithDot, stubModulesByName,
25281 context = layer.context,
25283 onLayerEndAdded = {};
25285 //Use override settings, particularly for pragmas
25286 //Do this before the var readings since it reads config values.
25287 if (module.override) {
25288 config = build.createOverrideConfig(config, module.override);
25291 namespace = config.namespace || '';
25292 namespaceWithDot = namespace ? namespace + '.' : '';
25293 stubModulesByName = (module.stubModules && module.stubModules._byName) || {};
25295 //Start build output for the module.
25296 module.onCompleteData = {
25298 path: (config.dir ? module._buildPath.replace(config.dir, "") : module._buildPath),
25302 buildFileContents += "\n" +
25303 module.onCompleteData.path +
25304 "\n----------------\n";
25306 //If there was an existing file with require in it, hoist to the top.
25307 if (layer.existingRequireUrl) {
25308 reqIndex = layer.buildFilePaths.indexOf(layer.existingRequireUrl);
25309 if (reqIndex !== -1) {
25310 layer.buildFilePaths.splice(reqIndex, 1);
25311 layer.buildFilePaths.unshift(layer.existingRequireUrl);
25315 if (config.generateSourceMaps) {
25316 sourceMapBase = config.dir || config.baseUrl;
25317 sourceMapGenerator = new SourceMapGenerator.SourceMapGenerator({
25318 file: module._buildPath.replace(sourceMapBase, '')
25322 //Write the built module to disk, and build up the build output.
25324 return prim.serial(layer.buildFilePaths.map(function (path) {
25325 return function () {
25327 singleContents = '';
25329 moduleName = layer.buildFileToModule[path];
25330 //If the moduleName is for a package main, then update it to the
25332 packageConfig = layer.context.config.pkgs &&
25333 getOwn(layer.context.config.pkgs, moduleName);
25334 if (packageConfig) {
25335 nonPackageName = moduleName;
25336 moduleName += '/' + packageConfig.main;
25339 return prim().start(function () {
25340 //Figure out if the module is a result of a build plugin, and if so,
25341 //then delegate to that plugin.
25342 parts = context.makeModuleMap(moduleName);
25343 builder = parts.prefix && getOwn(context.defined, parts.prefix);
25345 if (builder.onLayerEnd && falseProp(onLayerEndAdded, parts.prefix)) {
25346 onLayerEnds.push(builder);
25347 onLayerEndAdded[parts.prefix] = true;
25350 if (builder.write) {
25351 writeApi = function (input) {
25352 singleContents += "\n" + addSemiColon(input, config);
25353 if (config.onBuildWrite) {
25354 singleContents = config.onBuildWrite(moduleName, path, singleContents);
25357 writeApi.asModule = function (moduleName, input) {
25358 singleContents += "\n" +
25359 addSemiColon(build.toTransport(namespace, moduleName, path, input, layer, {
25360 useSourceUrl: layer.context.config.useSourceUrl
25362 if (config.onBuildWrite) {
25363 singleContents = config.onBuildWrite(moduleName, path, singleContents);
25366 builder.write(parts.prefix, parts.name, writeApi);
25370 return prim().start(function () {
25371 if (hasProp(stubModulesByName, moduleName)) {
25372 //Just want to insert a simple module definition instead
25373 //of the source module. Useful for plugins that inline
25374 //all their resources.
25375 if (hasProp(layer.context.plugins, moduleName)) {
25376 //Slightly different content for plugins, to indicate
25377 //that dynamic loading will not work.
25378 return 'define({load: function(id){throw new Error("Dynamic load not allowed: " + id);}});';
25380 return 'define({});';
25383 return require._cacheReadAsync(path);
25385 }).then(function (text) {
25386 var hasPackageName;
25388 currContents = text;
25390 if (config.cjsTranslate &&
25391 (!config.shim || !lang.hasProp(config.shim, moduleName))) {
25392 currContents = commonJs.convert(path, currContents);
25395 if (config.onBuildRead) {
25396 currContents = config.onBuildRead(moduleName, path, currContents);
25399 if (packageConfig) {
25400 hasPackageName = (nonPackageName === parse.getNamedDefine(currContents));
25404 currContents = pragma.namespace(currContents, namespace);
25407 currContents = build.toTransport(namespace, moduleName, path, currContents, layer, {
25408 useSourceUrl: config.useSourceUrl
25411 if (packageConfig && !hasPackageName) {
25412 currContents = addSemiColon(currContents, config) + '\n';
25413 currContents += namespaceWithDot + "define('" +
25414 packageConfig.name + "', ['" + moduleName +
25415 "'], function (main) { return main; });\n";
25418 if (config.onBuildWrite) {
25419 currContents = config.onBuildWrite(moduleName, path, currContents);
25422 //Semicolon is for files that are not well formed when
25423 //concatenated with other content.
25424 singleContents += "\n" + addSemiColon(currContents, config);
25427 }).then(function () {
25428 var sourceMapPath, sourceMapLineNumber,
25429 shortPath = path.replace(config.dir, "");
25431 module.onCompleteData.included.push(shortPath);
25432 buildFileContents += shortPath + "\n";
25434 //Some files may not have declared a require module, and if so,
25435 //put in a placeholder call so the require does not try to load them
25436 //after the module is processed.
25437 //If we have a name, but no defined module, then add in the placeholder.
25438 if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) {
25439 shim = config.shim && (getOwn(config.shim, moduleName) || (packageConfig && getOwn(config.shim, nonPackageName)));
25441 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", ' +
25442 (shim.deps && shim.deps.length ?
25443 build.makeJsArrayString(shim.deps) + ', ' : '') +
25444 (shim.exportsFn ? shim.exportsFn() : 'function(){}') +
25447 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", function(){});\n';
25451 //Add to the source map
25452 if (sourceMapGenerator) {
25453 sourceMapPath = build.makeRelativeFilePath(module._buildPath, path);
25454 sourceMapLineNumber = fileContents.split('\n').length - 1;
25455 lineCount = singleContents.split('\n').length;
25456 for (var i = 1; i <= lineCount; i += 1) {
25457 sourceMapGenerator.addMapping({
25459 line: sourceMapLineNumber + i,
25466 source: sourceMapPath
25470 //Store the content of the original in the source
25471 //map since other transforms later like minification
25472 //can mess up translating back to the original
25474 sourceMapGenerator.setSourceContent(sourceMapPath, singleContents);
25477 //Add the file to the final contents
25478 fileContents += singleContents;
25481 })).then(function () {
25482 if (onLayerEnds.length) {
25483 onLayerEnds.forEach(function (builder) {
25485 if (typeof module.out === 'string') {
25487 } else if (typeof module._buildPath === 'string') {
25488 path = module._buildPath;
25490 builder.onLayerEnd(function (input) {
25491 fileContents += "\n" + addSemiColon(input, config);
25499 if (module.create) {
25500 //The ID is for a created layer. Write out
25501 //a module definition for it in case the
25502 //built file is used with enforceDefine
25504 fileContents += '\n' + namespaceWithDot + 'define("' + module.name + '", function(){});\n';
25507 //Add a require at the end to kick start module execution, if that
25508 //was desired. Usually this is only specified when using small shim
25509 //loaders like almond.
25510 if (module.insertRequire) {
25511 fileContents += '\n' + namespaceWithDot + 'require(["' + module.insertRequire.join('", "') + '"]);\n';
25514 }).then(function () {
25516 text: config.wrap ?
25517 config.wrap.start + fileContents + config.wrap.end :
25519 buildText: buildFileContents,
25520 sourceMap: sourceMapGenerator ?
25521 JSON.stringify(sourceMapGenerator.toJSON(), null, ' ') :
25527 //Converts an JS array of strings to a string representation.
25528 //Not using JSON.stringify() for Rhino's sake.
25529 build.makeJsArrayString = function (ary) {
25530 return '["' + ary.map(function (item) {
25531 //Escape any double quotes, backslashes
25532 return lang.jsEscape(item);
25533 }).join('","') + '"]';
25536 build.toTransport = function (namespace, moduleName, path, contents, layer, options) {
25537 var baseUrl = layer && layer.context.config.baseUrl;
25539 function onFound(info) {
25540 //Only mark this module as having a name if not a named module,
25541 //or if a named module and the name matches expectations.
25542 if (layer && (info.needsId || info.foundId === moduleName)) {
25543 layer.modulesWithNames[moduleName] = true;
25547 //Convert path to be a local one to the baseUrl, useful for
25550 path = path.replace(baseUrl, '');
25553 return transform.toTransport(namespace, moduleName, path, contents, onFound, options);
25563 * Sets the default baseUrl for requirejs to be directory of top level
25566 function setBaseUrl(fileName) {
25567 //Use the file name's directory as the baseUrl if available.
25568 dir = fileName.replace(/\\/g, '/');
25569 if (dir.indexOf('/') !== -1) {
25570 dir = dir.split('/');
25572 dir = dir.join('/');
25573 exec("require({baseUrl: '" + dir + "'});");
25577 function createRjsApi() {
25578 //Create a method that will run the optimzer given an object
25580 requirejs.optimize = function (config, callback, errback) {
25581 if (!loadedOptimizedLib) {
25583 loadedOptimizedLib = true;
25586 //Create the function that will be called once build modules
25587 //have been loaded.
25588 var runBuild = function (build, logger, quit) {
25589 //Make sure config has a log level, and if not,
25590 //make it "silent" by default.
25591 config.logLevel = config.hasOwnProperty('logLevel') ?
25592 config.logLevel : logger.SILENT;
25594 //Reset build internals first in case this is part
25595 //of a long-running server process that could have
25596 //exceptioned out in a bad state. It is only defined
25597 //after the first call though.
25598 if (requirejs._buildReset) {
25599 requirejs._buildReset();
25600 requirejs._cacheReset();
25603 function done(result) {
25604 //And clean up, in case something else triggers
25605 //a build in another pathway.
25606 if (requirejs._buildReset) {
25607 requirejs._buildReset();
25608 requirejs._cacheReset();
25611 // Ensure errors get propagated to the errback
25612 if (result instanceof Error) {
25619 errback = errback || function (err) {
25620 // Using console here since logger may have
25621 // turned off error logging. Since quit is
25622 // called want to be sure a message is printed.
25627 build(config).then(done, done).then(callback, errback);
25632 }, ['build', 'logger', 'env!env/quit'], runBuild);
25635 requirejs.tools = {
25636 useLib: function (contextName, callback) {
25638 callback = contextName;
25639 contextName = 'uselib';
25642 if (!useLibLoaded[contextName]) {
25644 useLibLoaded[contextName] = true;
25647 var req = requirejs({
25648 context: contextName
25651 req(['build'], function () {
25657 requirejs.define = define;
25660 //If in Node, and included via a require('requirejs'), just export and
25661 //THROW IT ON THE GROUND!
25662 if (env === 'node' && reqMain !== module) {
25663 setBaseUrl(path.resolve(reqMain ? reqMain.filename : '.'));
25667 module.exports = requirejs;
25669 } else if (env === 'browser') {
25670 //Only option is to use the API.
25671 setBaseUrl(location.href);
25674 } else if ((env === 'rhino' || env === 'xpconnect') &&
25675 //User sets up requirejsAsLib variable to indicate it is loaded
25676 //via load() to be used as a library.
25677 typeof requirejsAsLib !== 'undefined' && requirejsAsLib) {
25678 //This script is loaded via rhino's load() method, expose the
25680 setBaseUrl(fileName);
25685 if (commandOption === 'o') {
25686 //Do the optimizer work.
25690 * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
25691 * Available via the MIT or new BSD license.
25692 * see: http://github.com/jrburke/requirejs for details
25696 * Create a build.js file that has the build options you want and pass that
25697 * build file to this file to do the build. See example.build.js for more information.
25700 /*jslint strict: false, nomen: false */
25701 /*global require: false */
25704 baseUrl: require.s.contexts._.config.baseUrl,
25705 //Use a separate context than the default context so that the
25706 //build can use the default context.
25711 }, ['env!env/args', 'env!env/quit', 'logger', 'build'],
25712 function (args, quit, logger, build) {
25713 build(args).then(function () {}, function (err) {
25720 } else if (commandOption === 'v') {
25721 console.log('r.js: ' + version +
25722 ', RequireJS: ' + this.requirejsVars.require.version +
25723 ', UglifyJS2: 2.3.6, UglifyJS: 1.3.4');
25724 } else if (commandOption === 'convert') {
25727 this.requirejsVars.require(['env!env/args', 'commonJs', 'env!env/print'],
25728 function (args, commonJs, print) {
25730 var srcDir, outDir;
25734 if (!srcDir || !outDir) {
25735 print('Usage: path/to/commonjs/modules output/dir');
25739 commonJs.convertDir(args[0], args[1]);
25744 //Load the bundled libraries for use in the app.
25745 if (commandOption === 'lib') {
25749 setBaseUrl(fileName);
25751 if (exists(fileName)) {
25752 exec(readFile(fileName), fileName);
25758 }((typeof console !== 'undefined' ? console : undefined),
25759 (typeof Packages !== 'undefined' || (typeof window === 'undefined' &&
25760 typeof Components !== 'undefined' && Components.interfaces) ?
25761 Array.prototype.slice.call(arguments, 0) : []),
25762 (typeof readFile !== 'undefined' ? readFile : undefined)));