UNPKG

1.19 MBJavaScriptView Raw
1#!/usr/bin/env node
2/**
3 * @license r.js 2.1.22 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
4 * Available via the MIT or new BSD license.
5 * see: http://github.com/jrburke/requirejs for details
6 */
7
8/*
9 * This is a bootstrap script to allow running RequireJS in the command line
10 * in either a Java/Rhino or Node environment. It is modified by the top-level
11 * dist.js file to inject other files to completely enable this file. It is
12 * the shell of the r.js file.
13 */
14
15/*jslint evil: true, nomen: true, sloppy: true */
16/*global readFile: true, process: false, Packages: false, print: false,
17console: false, java: false, module: false, requirejsVars, navigator,
18document, importScripts, self, location, Components, FileUtils */
19
20var requirejs, require, define, xpcUtil;
21(function (console, args, readFileFunc) {
22 var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire,
23 nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci,
24 version = '2.1.22',
25 jsSuffixRegExp = /\.js$/,
26 commandOption = '',
27 useLibLoaded = {},
28 //Used by jslib/rhino/args.js
29 rhinoArgs = args,
30 //Used by jslib/xpconnect/args.js
31 xpconnectArgs = args,
32 readFile = typeof readFileFunc !== 'undefined' ? readFileFunc : null;
33
34 function showHelp() {
35 console.log('See https://github.com/jrburke/r.js for usage.');
36 }
37
38 if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') ||
39 (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) {
40 env = 'browser';
41
42 readFile = function (path) {
43 return fs.readFileSync(path, 'utf8');
44 };
45
46 exec = function (string) {
47 return eval(string);
48 };
49
50 exists = function () {
51 console.log('x.js exists not applicable in browser env');
52 return false;
53 };
54
55 } else if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
56 env = 'node';
57
58 //Get the fs module via Node's require before it
59 //gets replaced. Used in require/node.js
60 fs = require('fs');
61 vm = require('vm');
62 path = require('path');
63 //In Node 0.7+ existsSync is on fs.
64 existsForNode = fs.existsSync || path.existsSync;
65
66 nodeRequire = require;
67 nodeDefine = define;
68 reqMain = require.main;
69
70 //Temporarily hide require and define to allow require.js to define
71 //them.
72 require = undefined;
73 define = undefined;
74
75 readFile = function (path) {
76 return fs.readFileSync(path, 'utf8');
77 };
78
79 exec = function (string, name) {
80 return vm.runInThisContext(this.requirejsVars.require.makeNodeWrapper(string),
81 name ? fs.realpathSync(name) : '');
82 };
83
84 exists = function (fileName) {
85 return existsForNode(fileName);
86 };
87
88
89 fileName = process.argv[2];
90
91 if (fileName && fileName.indexOf('-') === 0) {
92 commandOption = fileName.substring(1);
93 fileName = process.argv[3];
94 }
95 } else if (typeof Packages !== 'undefined') {
96 env = 'rhino';
97
98 fileName = args[0];
99
100 if (fileName && fileName.indexOf('-') === 0) {
101 commandOption = fileName.substring(1);
102 fileName = args[1];
103 }
104
105 //Exec/readFile differs between Rhino and Nashorn. Rhino has an
106 //importPackage where Nashorn does not, so branch on that. This is a
107 //coarser check -- detecting readFile existence might also be enough for
108 //this spot. However, sticking with importPackage to keep it the same
109 //as other Rhino/Nashorn detection branches.
110 if (typeof importPackage !== 'undefined') {
111 rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext();
112
113 exec = function (string, name) {
114 return rhinoContext.evaluateString(this, string, name, 0, null);
115 };
116 } else {
117 exec = function (string, name) {
118 load({ script: string, name: name});
119 };
120 readFile = readFully;
121 }
122
123 exists = function (fileName) {
124 return (new java.io.File(fileName)).exists();
125 };
126
127 //Define a console.log for easier logging. Don't
128 //get fancy though.
129 if (typeof console === 'undefined') {
130 console = {
131 log: function () {
132 print.apply(undefined, arguments);
133 }
134 };
135 }
136 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) {
137 env = 'xpconnect';
138
139 Components.utils['import']('resource://gre/modules/FileUtils.jsm');
140 Cc = Components.classes;
141 Ci = Components.interfaces;
142
143 fileName = args[0];
144
145 if (fileName && fileName.indexOf('-') === 0) {
146 commandOption = fileName.substring(1);
147 fileName = args[1];
148 }
149
150 xpcUtil = {
151 isWindows: ('@mozilla.org/windows-registry-key;1' in Cc),
152 cwd: function () {
153 return FileUtils.getFile("CurWorkD", []).path;
154 },
155
156 //Remove . and .. from paths, normalize on front slashes
157 normalize: function (path) {
158 //There has to be an easier way to do this.
159 var i, part, ary,
160 firstChar = path.charAt(0);
161
162 if (firstChar !== '/' &&
163 firstChar !== '\\' &&
164 path.indexOf(':') === -1) {
165 //A relative path. Use the current working directory.
166 path = xpcUtil.cwd() + '/' + path;
167 }
168
169 ary = path.replace(/\\/g, '/').split('/');
170
171 for (i = 0; i < ary.length; i += 1) {
172 part = ary[i];
173 if (part === '.') {
174 ary.splice(i, 1);
175 i -= 1;
176 } else if (part === '..') {
177 ary.splice(i - 1, 2);
178 i -= 2;
179 }
180 }
181 return ary.join('/');
182 },
183
184 xpfile: function (path) {
185 var fullPath;
186 try {
187 fullPath = xpcUtil.normalize(path);
188 if (xpcUtil.isWindows) {
189 fullPath = fullPath.replace(/\//g, '\\');
190 }
191 return new FileUtils.File(fullPath);
192 } catch (e) {
193 throw new Error((fullPath || path) + ' failed: ' + e);
194 }
195 },
196
197 readFile: function (/*String*/path, /*String?*/encoding) {
198 //A file read function that can deal with BOMs
199 encoding = encoding || "utf-8";
200
201 var inStream, convertStream,
202 readData = {},
203 fileObj = xpcUtil.xpfile(path);
204
205 //XPCOM, you so crazy
206 try {
207 inStream = Cc['@mozilla.org/network/file-input-stream;1']
208 .createInstance(Ci.nsIFileInputStream);
209 inStream.init(fileObj, 1, 0, false);
210
211 convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
212 .createInstance(Ci.nsIConverterInputStream);
213 convertStream.init(inStream, encoding, inStream.available(),
214 Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
215
216 convertStream.readString(inStream.available(), readData);
217 return readData.value;
218 } catch (e) {
219 throw new Error((fileObj && fileObj.path || '') + ': ' + e);
220 } finally {
221 if (convertStream) {
222 convertStream.close();
223 }
224 if (inStream) {
225 inStream.close();
226 }
227 }
228 }
229 };
230
231 readFile = xpcUtil.readFile;
232
233 exec = function (string) {
234 return eval(string);
235 };
236
237 exists = function (fileName) {
238 return xpcUtil.xpfile(fileName).exists();
239 };
240
241 //Define a console.log for easier logging. Don't
242 //get fancy though.
243 if (typeof console === 'undefined') {
244 console = {
245 log: function () {
246 print.apply(undefined, arguments);
247 }
248 };
249 }
250 }
251
252 /** vim: et:ts=4:sw=4:sts=4
253 * @license RequireJS 2.1.22 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
254 * Available via the MIT or new BSD license.
255 * see: http://github.com/jrburke/requirejs for details
256 */
257//Not using strict: uneven strict support in browsers, #392, and causes
258//problems with requirejs.exec()/transpiler plugins that may not be strict.
259/*jslint regexp: true, nomen: true, sloppy: true */
260/*global window, navigator, document, importScripts, setTimeout, opera */
261
262
263(function (global) {
264 var req, s, head, baseElement, dataMain, src,
265 interactiveScript, currentlyAddingScript, mainScript, subPath,
266 version = '2.1.22',
267 commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
268 cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
269 jsSuffixRegExp = /\.js$/,
270 currDirRegExp = /^\.\//,
271 op = Object.prototype,
272 ostring = op.toString,
273 hasOwn = op.hasOwnProperty,
274 ap = Array.prototype,
275 isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
276 isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
277 //PS3 indicates loaded and complete, but need to wait for complete
278 //specifically. Sequence is 'loading', 'loaded', execution,
279 // then 'complete'. The UA check is unfortunate, but not sure how
280 //to feature test w/o causing perf issues.
281 readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
282 /^complete$/ : /^(complete|loaded)$/,
283 defContextName = '_',
284 //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
285 isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
286 contexts = {},
287 cfg = {},
288 globalDefQueue = [],
289 useInteractive = false;
290
291 function isFunction(it) {
292 return ostring.call(it) === '[object Function]';
293 }
294
295 function isArray(it) {
296 return ostring.call(it) === '[object Array]';
297 }
298
299 /**
300 * Helper function for iterating over an array. If the func returns
301 * a true value, it will break out of the loop.
302 */
303 function each(ary, func) {
304 if (ary) {
305 var i;
306 for (i = 0; i < ary.length; i += 1) {
307 if (ary[i] && func(ary[i], i, ary)) {
308 break;
309 }
310 }
311 }
312 }
313
314 /**
315 * Helper function for iterating over an array backwards. If the func
316 * returns a true value, it will break out of the loop.
317 */
318 function eachReverse(ary, func) {
319 if (ary) {
320 var i;
321 for (i = ary.length - 1; i > -1; i -= 1) {
322 if (ary[i] && func(ary[i], i, ary)) {
323 break;
324 }
325 }
326 }
327 }
328
329 function hasProp(obj, prop) {
330 return hasOwn.call(obj, prop);
331 }
332
333 function getOwn(obj, prop) {
334 return hasProp(obj, prop) && obj[prop];
335 }
336
337 /**
338 * Cycles over properties in an object and calls a function for each
339 * property value. If the function returns a truthy value, then the
340 * iteration is stopped.
341 */
342 function eachProp(obj, func) {
343 var prop;
344 for (prop in obj) {
345 if (hasProp(obj, prop)) {
346 if (func(obj[prop], prop)) {
347 break;
348 }
349 }
350 }
351 }
352
353 /**
354 * Simple function to mix in properties from source into target,
355 * but only if target does not already have a property of the same name.
356 */
357 function mixin(target, source, force, deepStringMixin) {
358 if (source) {
359 eachProp(source, function (value, prop) {
360 if (force || !hasProp(target, prop)) {
361 if (deepStringMixin && typeof value === 'object' && value &&
362 !isArray(value) && !isFunction(value) &&
363 !(value instanceof RegExp)) {
364
365 if (!target[prop]) {
366 target[prop] = {};
367 }
368 mixin(target[prop], value, force, deepStringMixin);
369 } else {
370 target[prop] = value;
371 }
372 }
373 });
374 }
375 return target;
376 }
377
378 //Similar to Function.prototype.bind, but the 'this' object is specified
379 //first, since it is easier to read/figure out what 'this' will be.
380 function bind(obj, fn) {
381 return function () {
382 return fn.apply(obj, arguments);
383 };
384 }
385
386 function scripts() {
387 return document.getElementsByTagName('script');
388 }
389
390 function defaultOnError(err) {
391 throw err;
392 }
393
394 //Allow getting a global that is expressed in
395 //dot notation, like 'a.b.c'.
396 function getGlobal(value) {
397 if (!value) {
398 return value;
399 }
400 var g = global;
401 each(value.split('.'), function (part) {
402 g = g[part];
403 });
404 return g;
405 }
406
407 /**
408 * Constructs an error with a pointer to an URL with more information.
409 * @param {String} id the error ID that maps to an ID on a web page.
410 * @param {String} message human readable error.
411 * @param {Error} [err] the original error, if there is one.
412 *
413 * @returns {Error}
414 */
415 function makeError(id, msg, err, requireModules) {
416 var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
417 e.requireType = id;
418 e.requireModules = requireModules;
419 if (err) {
420 e.originalError = err;
421 }
422 return e;
423 }
424
425 if (typeof define !== 'undefined') {
426 //If a define is already in play via another AMD loader,
427 //do not overwrite.
428 return;
429 }
430
431 if (typeof requirejs !== 'undefined') {
432 if (isFunction(requirejs)) {
433 //Do not overwrite an existing requirejs instance.
434 return;
435 }
436 cfg = requirejs;
437 requirejs = undefined;
438 }
439
440 //Allow for a require config object
441 if (typeof require !== 'undefined' && !isFunction(require)) {
442 //assume it is a config object.
443 cfg = require;
444 require = undefined;
445 }
446
447 function newContext(contextName) {
448 var inCheckLoaded, Module, context, handlers,
449 checkLoadedTimeoutId,
450 config = {
451 //Defaults. Do not set a default for map
452 //config to speed up normalize(), which
453 //will run faster if there is no default.
454 waitSeconds: 7,
455 baseUrl: './',
456 paths: {},
457 bundles: {},
458 pkgs: {},
459 shim: {},
460 config: {}
461 },
462 registry = {},
463 //registry of just enabled modules, to speed
464 //cycle breaking code when lots of modules
465 //are registered, but not activated.
466 enabledRegistry = {},
467 undefEvents = {},
468 defQueue = [],
469 defined = {},
470 urlFetched = {},
471 bundlesMap = {},
472 requireCounter = 1,
473 unnormalizedCounter = 1;
474
475 /**
476 * Trims the . and .. from an array of path segments.
477 * It will keep a leading path segment if a .. will become
478 * the first path segment, to help with module name lookups,
479 * which act like paths, but can be remapped. But the end result,
480 * all paths that use this function should look normalized.
481 * NOTE: this method MODIFIES the input array.
482 * @param {Array} ary the array of path segments.
483 */
484 function trimDots(ary) {
485 var i, part;
486 for (i = 0; i < ary.length; i++) {
487 part = ary[i];
488 if (part === '.') {
489 ary.splice(i, 1);
490 i -= 1;
491 } else if (part === '..') {
492 // If at the start, or previous value is still ..,
493 // keep them so that when converted to a path it may
494 // still work when converted to a path, even though
495 // as an ID it is less than ideal. In larger point
496 // releases, may be better to just kick out an error.
497 if (i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1] === '..') {
498 continue;
499 } else if (i > 0) {
500 ary.splice(i - 1, 2);
501 i -= 2;
502 }
503 }
504 }
505 }
506
507 /**
508 * Given a relative module name, like ./something, normalize it to
509 * a real name that can be mapped to a path.
510 * @param {String} name the relative name
511 * @param {String} baseName a real name that the name arg is relative
512 * to.
513 * @param {Boolean} applyMap apply the map config to the value. Should
514 * only be done if this normalization is for a dependency ID.
515 * @returns {String} normalized name
516 */
517 function normalize(name, baseName, applyMap) {
518 var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
519 foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
520 baseParts = (baseName && baseName.split('/')),
521 map = config.map,
522 starMap = map && map['*'];
523
524 //Adjust any relative paths.
525 if (name) {
526 name = name.split('/');
527 lastIndex = name.length - 1;
528
529 // If wanting node ID compatibility, strip .js from end
530 // of IDs. Have to do this here, and not in nameToUrl
531 // because node allows either .js or non .js to map
532 // to same file.
533 if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
534 name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
535 }
536
537 // Starts with a '.' so need the baseName
538 if (name[0].charAt(0) === '.' && baseParts) {
539 //Convert baseName to array, and lop off the last part,
540 //so that . matches that 'directory' and not name of the baseName's
541 //module. For instance, baseName of 'one/two/three', maps to
542 //'one/two/three.js', but we want the directory, 'one/two' for
543 //this normalization.
544 normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
545 name = normalizedBaseParts.concat(name);
546 }
547
548 trimDots(name);
549 name = name.join('/');
550 }
551
552 //Apply map config if available.
553 if (applyMap && map && (baseParts || starMap)) {
554 nameParts = name.split('/');
555
556 outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
557 nameSegment = nameParts.slice(0, i).join('/');
558
559 if (baseParts) {
560 //Find the longest baseName segment match in the config.
561 //So, do joins on the biggest to smallest lengths of baseParts.
562 for (j = baseParts.length; j > 0; j -= 1) {
563 mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
564
565 //baseName segment has config, find if it has one for
566 //this name.
567 if (mapValue) {
568 mapValue = getOwn(mapValue, nameSegment);
569 if (mapValue) {
570 //Match, update name to the new value.
571 foundMap = mapValue;
572 foundI = i;
573 break outerLoop;
574 }
575 }
576 }
577 }
578
579 //Check for a star map match, but just hold on to it,
580 //if there is a shorter segment match later in a matching
581 //config, then favor over this star map.
582 if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
583 foundStarMap = getOwn(starMap, nameSegment);
584 starI = i;
585 }
586 }
587
588 if (!foundMap && foundStarMap) {
589 foundMap = foundStarMap;
590 foundI = starI;
591 }
592
593 if (foundMap) {
594 nameParts.splice(0, foundI, foundMap);
595 name = nameParts.join('/');
596 }
597 }
598
599 // If the name points to a package's name, use
600 // the package main instead.
601 pkgMain = getOwn(config.pkgs, name);
602
603 return pkgMain ? pkgMain : name;
604 }
605
606 function removeScript(name) {
607 if (isBrowser) {
608 each(scripts(), function (scriptNode) {
609 if (scriptNode.getAttribute('data-requiremodule') === name &&
610 scriptNode.getAttribute('data-requirecontext') === context.contextName) {
611 scriptNode.parentNode.removeChild(scriptNode);
612 return true;
613 }
614 });
615 }
616 }
617
618 function hasPathFallback(id) {
619 var pathConfig = getOwn(config.paths, id);
620 if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
621 //Pop off the first array value, since it failed, and
622 //retry
623 pathConfig.shift();
624 context.require.undef(id);
625
626 //Custom require that does not do map translation, since
627 //ID is "absolute", already mapped/resolved.
628 context.makeRequire(null, {
629 skipMap: true
630 })([id]);
631
632 return true;
633 }
634 }
635
636 //Turns a plugin!resource to [plugin, resource]
637 //with the plugin being undefined if the name
638 //did not have a plugin prefix.
639 function splitPrefix(name) {
640 var prefix,
641 index = name ? name.indexOf('!') : -1;
642 if (index > -1) {
643 prefix = name.substring(0, index);
644 name = name.substring(index + 1, name.length);
645 }
646 return [prefix, name];
647 }
648
649 /**
650 * Creates a module mapping that includes plugin prefix, module
651 * name, and path. If parentModuleMap is provided it will
652 * also normalize the name via require.normalize()
653 *
654 * @param {String} name the module name
655 * @param {String} [parentModuleMap] parent module map
656 * for the module name, used to resolve relative names.
657 * @param {Boolean} isNormalized: is the ID already normalized.
658 * This is true if this call is done for a define() module ID.
659 * @param {Boolean} applyMap: apply the map config to the ID.
660 * Should only be true if this map is for a dependency.
661 *
662 * @returns {Object}
663 */
664 function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
665 var url, pluginModule, suffix, nameParts,
666 prefix = null,
667 parentName = parentModuleMap ? parentModuleMap.name : null,
668 originalName = name,
669 isDefine = true,
670 normalizedName = '';
671
672 //If no name, then it means it is a require call, generate an
673 //internal name.
674 if (!name) {
675 isDefine = false;
676 name = '_@r' + (requireCounter += 1);
677 }
678
679 nameParts = splitPrefix(name);
680 prefix = nameParts[0];
681 name = nameParts[1];
682
683 if (prefix) {
684 prefix = normalize(prefix, parentName, applyMap);
685 pluginModule = getOwn(defined, prefix);
686 }
687
688 //Account for relative paths if there is a base name.
689 if (name) {
690 if (prefix) {
691 if (pluginModule && pluginModule.normalize) {
692 //Plugin is loaded, use its normalize method.
693 normalizedName = pluginModule.normalize(name, function (name) {
694 return normalize(name, parentName, applyMap);
695 });
696 } else {
697 // If nested plugin references, then do not try to
698 // normalize, as it will not normalize correctly. This
699 // places a restriction on resourceIds, and the longer
700 // term solution is not to normalize until plugins are
701 // loaded and all normalizations to allow for async
702 // loading of a loader plugin. But for now, fixes the
703 // common uses. Details in #1131
704 normalizedName = name.indexOf('!') === -1 ?
705 normalize(name, parentName, applyMap) :
706 name;
707 }
708 } else {
709 //A regular module.
710 normalizedName = normalize(name, parentName, applyMap);
711
712 //Normalized name may be a plugin ID due to map config
713 //application in normalize. The map config values must
714 //already be normalized, so do not need to redo that part.
715 nameParts = splitPrefix(normalizedName);
716 prefix = nameParts[0];
717 normalizedName = nameParts[1];
718 isNormalized = true;
719
720 url = context.nameToUrl(normalizedName);
721 }
722 }
723
724 //If the id is a plugin id that cannot be determined if it needs
725 //normalization, stamp it with a unique ID so two matching relative
726 //ids that may conflict can be separate.
727 suffix = prefix && !pluginModule && !isNormalized ?
728 '_unnormalized' + (unnormalizedCounter += 1) :
729 '';
730
731 return {
732 prefix: prefix,
733 name: normalizedName,
734 parentMap: parentModuleMap,
735 unnormalized: !!suffix,
736 url: url,
737 originalName: originalName,
738 isDefine: isDefine,
739 id: (prefix ?
740 prefix + '!' + normalizedName :
741 normalizedName) + suffix
742 };
743 }
744
745 function getModule(depMap) {
746 var id = depMap.id,
747 mod = getOwn(registry, id);
748
749 if (!mod) {
750 mod = registry[id] = new context.Module(depMap);
751 }
752
753 return mod;
754 }
755
756 function on(depMap, name, fn) {
757 var id = depMap.id,
758 mod = getOwn(registry, id);
759
760 if (hasProp(defined, id) &&
761 (!mod || mod.defineEmitComplete)) {
762 if (name === 'defined') {
763 fn(defined[id]);
764 }
765 } else {
766 mod = getModule(depMap);
767 if (mod.error && name === 'error') {
768 fn(mod.error);
769 } else {
770 mod.on(name, fn);
771 }
772 }
773 }
774
775 function onError(err, errback) {
776 var ids = err.requireModules,
777 notified = false;
778
779 if (errback) {
780 errback(err);
781 } else {
782 each(ids, function (id) {
783 var mod = getOwn(registry, id);
784 if (mod) {
785 //Set error on module, so it skips timeout checks.
786 mod.error = err;
787 if (mod.events.error) {
788 notified = true;
789 mod.emit('error', err);
790 }
791 }
792 });
793
794 if (!notified) {
795 req.onError(err);
796 }
797 }
798 }
799
800 /**
801 * Internal method to transfer globalQueue items to this context's
802 * defQueue.
803 */
804 function takeGlobalQueue() {
805 //Push all the globalDefQueue items into the context's defQueue
806 if (globalDefQueue.length) {
807 each(globalDefQueue, function(queueItem) {
808 var id = queueItem[0];
809 if (typeof id === 'string') {
810 context.defQueueMap[id] = true;
811 }
812 defQueue.push(queueItem);
813 });
814 globalDefQueue = [];
815 }
816 }
817
818 handlers = {
819 'require': function (mod) {
820 if (mod.require) {
821 return mod.require;
822 } else {
823 return (mod.require = context.makeRequire(mod.map));
824 }
825 },
826 'exports': function (mod) {
827 mod.usingExports = true;
828 if (mod.map.isDefine) {
829 if (mod.exports) {
830 return (defined[mod.map.id] = mod.exports);
831 } else {
832 return (mod.exports = defined[mod.map.id] = {});
833 }
834 }
835 },
836 'module': function (mod) {
837 if (mod.module) {
838 return mod.module;
839 } else {
840 return (mod.module = {
841 id: mod.map.id,
842 uri: mod.map.url,
843 config: function () {
844 return getOwn(config.config, mod.map.id) || {};
845 },
846 exports: mod.exports || (mod.exports = {})
847 });
848 }
849 }
850 };
851
852 function cleanRegistry(id) {
853 //Clean up machinery used for waiting modules.
854 delete registry[id];
855 delete enabledRegistry[id];
856 }
857
858 function breakCycle(mod, traced, processed) {
859 var id = mod.map.id;
860
861 if (mod.error) {
862 mod.emit('error', mod.error);
863 } else {
864 traced[id] = true;
865 each(mod.depMaps, function (depMap, i) {
866 var depId = depMap.id,
867 dep = getOwn(registry, depId);
868
869 //Only force things that have not completed
870 //being defined, so still in the registry,
871 //and only if it has not been matched up
872 //in the module already.
873 if (dep && !mod.depMatched[i] && !processed[depId]) {
874 if (getOwn(traced, depId)) {
875 mod.defineDep(i, defined[depId]);
876 mod.check(); //pass false?
877 } else {
878 breakCycle(dep, traced, processed);
879 }
880 }
881 });
882 processed[id] = true;
883 }
884 }
885
886 function checkLoaded() {
887 var err, usingPathFallback,
888 waitInterval = config.waitSeconds * 1000,
889 //It is possible to disable the wait interval by using waitSeconds of 0.
890 expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
891 noLoads = [],
892 reqCalls = [],
893 stillLoading = false,
894 needCycleCheck = true;
895
896 //Do not bother if this call was a result of a cycle break.
897 if (inCheckLoaded) {
898 return;
899 }
900
901 inCheckLoaded = true;
902
903 //Figure out the state of all the modules.
904 eachProp(enabledRegistry, function (mod) {
905 var map = mod.map,
906 modId = map.id;
907
908 //Skip things that are not enabled or in error state.
909 if (!mod.enabled) {
910 return;
911 }
912
913 if (!map.isDefine) {
914 reqCalls.push(mod);
915 }
916
917 if (!mod.error) {
918 //If the module should be executed, and it has not
919 //been inited and time is up, remember it.
920 if (!mod.inited && expired) {
921 if (hasPathFallback(modId)) {
922 usingPathFallback = true;
923 stillLoading = true;
924 } else {
925 noLoads.push(modId);
926 removeScript(modId);
927 }
928 } else if (!mod.inited && mod.fetched && map.isDefine) {
929 stillLoading = true;
930 if (!map.prefix) {
931 //No reason to keep looking for unfinished
932 //loading. If the only stillLoading is a
933 //plugin resource though, keep going,
934 //because it may be that a plugin resource
935 //is waiting on a non-plugin cycle.
936 return (needCycleCheck = false);
937 }
938 }
939 }
940 });
941
942 if (expired && noLoads.length) {
943 //If wait time expired, throw error of unloaded modules.
944 err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
945 err.contextName = context.contextName;
946 return onError(err);
947 }
948
949 //Not expired, check for a cycle.
950 if (needCycleCheck) {
951 each(reqCalls, function (mod) {
952 breakCycle(mod, {}, {});
953 });
954 }
955
956 //If still waiting on loads, and the waiting load is something
957 //other than a plugin resource, or there are still outstanding
958 //scripts, then just try back later.
959 if ((!expired || usingPathFallback) && stillLoading) {
960 //Something is still waiting to load. Wait for it, but only
961 //if a timeout is not already in effect.
962 if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
963 checkLoadedTimeoutId = setTimeout(function () {
964 checkLoadedTimeoutId = 0;
965 checkLoaded();
966 }, 50);
967 }
968 }
969
970 inCheckLoaded = false;
971 }
972
973 Module = function (map) {
974 this.events = getOwn(undefEvents, map.id) || {};
975 this.map = map;
976 this.shim = getOwn(config.shim, map.id);
977 this.depExports = [];
978 this.depMaps = [];
979 this.depMatched = [];
980 this.pluginMaps = {};
981 this.depCount = 0;
982
983 /* this.exports this.factory
984 this.depMaps = [],
985 this.enabled, this.fetched
986 */
987 };
988
989 Module.prototype = {
990 init: function (depMaps, factory, errback, options) {
991 options = options || {};
992
993 //Do not do more inits if already done. Can happen if there
994 //are multiple define calls for the same module. That is not
995 //a normal, common case, but it is also not unexpected.
996 if (this.inited) {
997 return;
998 }
999
1000 this.factory = factory;
1001
1002 if (errback) {
1003 //Register for errors on this module.
1004 this.on('error', errback);
1005 } else if (this.events.error) {
1006 //If no errback already, but there are error listeners
1007 //on this module, set up an errback to pass to the deps.
1008 errback = bind(this, function (err) {
1009 this.emit('error', err);
1010 });
1011 }
1012
1013 //Do a copy of the dependency array, so that
1014 //source inputs are not modified. For example
1015 //"shim" deps are passed in here directly, and
1016 //doing a direct modification of the depMaps array
1017 //would affect that config.
1018 this.depMaps = depMaps && depMaps.slice(0);
1019
1020 this.errback = errback;
1021
1022 //Indicate this module has be initialized
1023 this.inited = true;
1024
1025 this.ignore = options.ignore;
1026
1027 //Could have option to init this module in enabled mode,
1028 //or could have been previously marked as enabled. However,
1029 //the dependencies are not known until init is called. So
1030 //if enabled previously, now trigger dependencies as enabled.
1031 if (options.enabled || this.enabled) {
1032 //Enable this module and dependencies.
1033 //Will call this.check()
1034 this.enable();
1035 } else {
1036 this.check();
1037 }
1038 },
1039
1040 defineDep: function (i, depExports) {
1041 //Because of cycles, defined callback for a given
1042 //export can be called more than once.
1043 if (!this.depMatched[i]) {
1044 this.depMatched[i] = true;
1045 this.depCount -= 1;
1046 this.depExports[i] = depExports;
1047 }
1048 },
1049
1050 fetch: function () {
1051 if (this.fetched) {
1052 return;
1053 }
1054 this.fetched = true;
1055
1056 context.startTime = (new Date()).getTime();
1057
1058 var map = this.map;
1059
1060 //If the manager is for a plugin managed resource,
1061 //ask the plugin to load it now.
1062 if (this.shim) {
1063 context.makeRequire(this.map, {
1064 enableBuildCallback: true
1065 })(this.shim.deps || [], bind(this, function () {
1066 return map.prefix ? this.callPlugin() : this.load();
1067 }));
1068 } else {
1069 //Regular dependency.
1070 return map.prefix ? this.callPlugin() : this.load();
1071 }
1072 },
1073
1074 load: function () {
1075 var url = this.map.url;
1076
1077 //Regular dependency.
1078 if (!urlFetched[url]) {
1079 urlFetched[url] = true;
1080 context.load(this.map.id, url);
1081 }
1082 },
1083
1084 /**
1085 * Checks if the module is ready to define itself, and if so,
1086 * define it.
1087 */
1088 check: function () {
1089 if (!this.enabled || this.enabling) {
1090 return;
1091 }
1092
1093 var err, cjsModule,
1094 id = this.map.id,
1095 depExports = this.depExports,
1096 exports = this.exports,
1097 factory = this.factory;
1098
1099 if (!this.inited) {
1100 // Only fetch if not already in the defQueue.
1101 if (!hasProp(context.defQueueMap, id)) {
1102 this.fetch();
1103 }
1104 } else if (this.error) {
1105 this.emit('error', this.error);
1106 } else if (!this.defining) {
1107 //The factory could trigger another require call
1108 //that would result in checking this module to
1109 //define itself again. If already in the process
1110 //of doing that, skip this work.
1111 this.defining = true;
1112
1113 if (this.depCount < 1 && !this.defined) {
1114 if (isFunction(factory)) {
1115 try {
1116 exports = context.execCb(id, factory, depExports, exports);
1117 } catch (e) {
1118 err = e;
1119 }
1120
1121 // Favor return value over exports. If node/cjs in play,
1122 // then will not have a return value anyway. Favor
1123 // module.exports assignment over exports object.
1124 if (this.map.isDefine && exports === undefined) {
1125 cjsModule = this.module;
1126 if (cjsModule) {
1127 exports = cjsModule.exports;
1128 } else if (this.usingExports) {
1129 //exports already set the defined value.
1130 exports = this.exports;
1131 }
1132 }
1133
1134 if (err) {
1135 // If there is an error listener, favor passing
1136 // to that instead of throwing an error. However,
1137 // only do it for define()'d modules. require
1138 // errbacks should not be called for failures in
1139 // their callbacks (#699). However if a global
1140 // onError is set, use that.
1141 if ((this.events.error && this.map.isDefine) ||
1142 req.onError !== defaultOnError) {
1143 err.requireMap = this.map;
1144 err.requireModules = this.map.isDefine ? [this.map.id] : null;
1145 err.requireType = this.map.isDefine ? 'define' : 'require';
1146 return onError((this.error = err));
1147 } else if (typeof console !== 'undefined' &&
1148 console.error) {
1149 // Log the error for debugging. If promises could be
1150 // used, this would be different, but making do.
1151 console.error(err);
1152 } else {
1153 // Do not want to completely lose the error. While this
1154 // will mess up processing and lead to similar results
1155 // as bug 1440, it at least surfaces the error.
1156 req.onError(err);
1157 }
1158 }
1159 } else {
1160 //Just a literal value
1161 exports = factory;
1162 }
1163
1164 this.exports = exports;
1165
1166 if (this.map.isDefine && !this.ignore) {
1167 defined[id] = exports;
1168
1169 if (req.onResourceLoad) {
1170 var resLoadMaps = [];
1171 each(this.depMaps, function (depMap) {
1172 resLoadMaps.push(depMap.normalizedMap || depMap);
1173 });
1174 req.onResourceLoad(context, this.map, resLoadMaps);
1175 }
1176 }
1177
1178 //Clean up
1179 cleanRegistry(id);
1180
1181 this.defined = true;
1182 }
1183
1184 //Finished the define stage. Allow calling check again
1185 //to allow define notifications below in the case of a
1186 //cycle.
1187 this.defining = false;
1188
1189 if (this.defined && !this.defineEmitted) {
1190 this.defineEmitted = true;
1191 this.emit('defined', this.exports);
1192 this.defineEmitComplete = true;
1193 }
1194
1195 }
1196 },
1197
1198 callPlugin: function () {
1199 var map = this.map,
1200 id = map.id,
1201 //Map already normalized the prefix.
1202 pluginMap = makeModuleMap(map.prefix);
1203
1204 //Mark this as a dependency for this plugin, so it
1205 //can be traced for cycles.
1206 this.depMaps.push(pluginMap);
1207
1208 on(pluginMap, 'defined', bind(this, function (plugin) {
1209 var load, normalizedMap, normalizedMod,
1210 bundleId = getOwn(bundlesMap, this.map.id),
1211 name = this.map.name,
1212 parentName = this.map.parentMap ? this.map.parentMap.name : null,
1213 localRequire = context.makeRequire(map.parentMap, {
1214 enableBuildCallback: true
1215 });
1216
1217 //If current map is not normalized, wait for that
1218 //normalized name to load instead of continuing.
1219 if (this.map.unnormalized) {
1220 //Normalize the ID if the plugin allows it.
1221 if (plugin.normalize) {
1222 name = plugin.normalize(name, function (name) {
1223 return normalize(name, parentName, true);
1224 }) || '';
1225 }
1226
1227 //prefix and name should already be normalized, no need
1228 //for applying map config again either.
1229 normalizedMap = makeModuleMap(map.prefix + '!' + name,
1230 this.map.parentMap);
1231 on(normalizedMap,
1232 'defined', bind(this, function (value) {
1233 this.map.normalizedMap = normalizedMap;
1234 this.init([], function () { return value; }, null, {
1235 enabled: true,
1236 ignore: true
1237 });
1238 }));
1239
1240 normalizedMod = getOwn(registry, normalizedMap.id);
1241 if (normalizedMod) {
1242 //Mark this as a dependency for this plugin, so it
1243 //can be traced for cycles.
1244 this.depMaps.push(normalizedMap);
1245
1246 if (this.events.error) {
1247 normalizedMod.on('error', bind(this, function (err) {
1248 this.emit('error', err);
1249 }));
1250 }
1251 normalizedMod.enable();
1252 }
1253
1254 return;
1255 }
1256
1257 //If a paths config, then just load that file instead to
1258 //resolve the plugin, as it is built into that paths layer.
1259 if (bundleId) {
1260 this.map.url = context.nameToUrl(bundleId);
1261 this.load();
1262 return;
1263 }
1264
1265 load = bind(this, function (value) {
1266 this.init([], function () { return value; }, null, {
1267 enabled: true
1268 });
1269 });
1270
1271 load.error = bind(this, function (err) {
1272 this.inited = true;
1273 this.error = err;
1274 err.requireModules = [id];
1275
1276 //Remove temp unnormalized modules for this module,
1277 //since they will never be resolved otherwise now.
1278 eachProp(registry, function (mod) {
1279 if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
1280 cleanRegistry(mod.map.id);
1281 }
1282 });
1283
1284 onError(err);
1285 });
1286
1287 //Allow plugins to load other code without having to know the
1288 //context or how to 'complete' the load.
1289 load.fromText = bind(this, function (text, textAlt) {
1290 /*jslint evil: true */
1291 var moduleName = map.name,
1292 moduleMap = makeModuleMap(moduleName),
1293 hasInteractive = useInteractive;
1294
1295 //As of 2.1.0, support just passing the text, to reinforce
1296 //fromText only being called once per resource. Still
1297 //support old style of passing moduleName but discard
1298 //that moduleName in favor of the internal ref.
1299 if (textAlt) {
1300 text = textAlt;
1301 }
1302
1303 //Turn off interactive script matching for IE for any define
1304 //calls in the text, then turn it back on at the end.
1305 if (hasInteractive) {
1306 useInteractive = false;
1307 }
1308
1309 //Prime the system by creating a module instance for
1310 //it.
1311 getModule(moduleMap);
1312
1313 //Transfer any config to this other module.
1314 if (hasProp(config.config, id)) {
1315 config.config[moduleName] = config.config[id];
1316 }
1317
1318 try {
1319 req.exec(text);
1320 } catch (e) {
1321 return onError(makeError('fromtexteval',
1322 'fromText eval for ' + id +
1323 ' failed: ' + e,
1324 e,
1325 [id]));
1326 }
1327
1328 if (hasInteractive) {
1329 useInteractive = true;
1330 }
1331
1332 //Mark this as a dependency for the plugin
1333 //resource
1334 this.depMaps.push(moduleMap);
1335
1336 //Support anonymous modules.
1337 context.completeLoad(moduleName);
1338
1339 //Bind the value of that module to the value for this
1340 //resource ID.
1341 localRequire([moduleName], load);
1342 });
1343
1344 //Use parentName here since the plugin's name is not reliable,
1345 //could be some weird string with no path that actually wants to
1346 //reference the parentName's path.
1347 plugin.load(map.name, localRequire, load, config);
1348 }));
1349
1350 context.enable(pluginMap, this);
1351 this.pluginMaps[pluginMap.id] = pluginMap;
1352 },
1353
1354 enable: function () {
1355 enabledRegistry[this.map.id] = this;
1356 this.enabled = true;
1357
1358 //Set flag mentioning that the module is enabling,
1359 //so that immediate calls to the defined callbacks
1360 //for dependencies do not trigger inadvertent load
1361 //with the depCount still being zero.
1362 this.enabling = true;
1363
1364 //Enable each dependency
1365 each(this.depMaps, bind(this, function (depMap, i) {
1366 var id, mod, handler;
1367
1368 if (typeof depMap === 'string') {
1369 //Dependency needs to be converted to a depMap
1370 //and wired up to this module.
1371 depMap = makeModuleMap(depMap,
1372 (this.map.isDefine ? this.map : this.map.parentMap),
1373 false,
1374 !this.skipMap);
1375 this.depMaps[i] = depMap;
1376
1377 handler = getOwn(handlers, depMap.id);
1378
1379 if (handler) {
1380 this.depExports[i] = handler(this);
1381 return;
1382 }
1383
1384 this.depCount += 1;
1385
1386 on(depMap, 'defined', bind(this, function (depExports) {
1387 if (this.undefed) {
1388 return;
1389 }
1390 this.defineDep(i, depExports);
1391 this.check();
1392 }));
1393
1394 if (this.errback) {
1395 on(depMap, 'error', bind(this, this.errback));
1396 } else if (this.events.error) {
1397 // No direct errback on this module, but something
1398 // else is listening for errors, so be sure to
1399 // propagate the error correctly.
1400 on(depMap, 'error', bind(this, function(err) {
1401 this.emit('error', err);
1402 }));
1403 }
1404 }
1405
1406 id = depMap.id;
1407 mod = registry[id];
1408
1409 //Skip special modules like 'require', 'exports', 'module'
1410 //Also, don't call enable if it is already enabled,
1411 //important in circular dependency cases.
1412 if (!hasProp(handlers, id) && mod && !mod.enabled) {
1413 context.enable(depMap, this);
1414 }
1415 }));
1416
1417 //Enable each plugin that is used in
1418 //a dependency
1419 eachProp(this.pluginMaps, bind(this, function (pluginMap) {
1420 var mod = getOwn(registry, pluginMap.id);
1421 if (mod && !mod.enabled) {
1422 context.enable(pluginMap, this);
1423 }
1424 }));
1425
1426 this.enabling = false;
1427
1428 this.check();
1429 },
1430
1431 on: function (name, cb) {
1432 var cbs = this.events[name];
1433 if (!cbs) {
1434 cbs = this.events[name] = [];
1435 }
1436 cbs.push(cb);
1437 },
1438
1439 emit: function (name, evt) {
1440 each(this.events[name], function (cb) {
1441 cb(evt);
1442 });
1443 if (name === 'error') {
1444 //Now that the error handler was triggered, remove
1445 //the listeners, since this broken Module instance
1446 //can stay around for a while in the registry.
1447 delete this.events[name];
1448 }
1449 }
1450 };
1451
1452 function callGetModule(args) {
1453 //Skip modules already defined.
1454 if (!hasProp(defined, args[0])) {
1455 getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
1456 }
1457 }
1458
1459 function removeListener(node, func, name, ieName) {
1460 //Favor detachEvent because of IE9
1461 //issue, see attachEvent/addEventListener comment elsewhere
1462 //in this file.
1463 if (node.detachEvent && !isOpera) {
1464 //Probably IE. If not it will throw an error, which will be
1465 //useful to know.
1466 if (ieName) {
1467 node.detachEvent(ieName, func);
1468 }
1469 } else {
1470 node.removeEventListener(name, func, false);
1471 }
1472 }
1473
1474 /**
1475 * Given an event from a script node, get the requirejs info from it,
1476 * and then removes the event listeners on the node.
1477 * @param {Event} evt
1478 * @returns {Object}
1479 */
1480 function getScriptData(evt) {
1481 //Using currentTarget instead of target for Firefox 2.0's sake. Not
1482 //all old browsers will be supported, but this one was easy enough
1483 //to support and still makes sense.
1484 var node = evt.currentTarget || evt.srcElement;
1485
1486 //Remove the listeners once here.
1487 removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
1488 removeListener(node, context.onScriptError, 'error');
1489
1490 return {
1491 node: node,
1492 id: node && node.getAttribute('data-requiremodule')
1493 };
1494 }
1495
1496 function intakeDefines() {
1497 var args;
1498
1499 //Any defined modules in the global queue, intake them now.
1500 takeGlobalQueue();
1501
1502 //Make sure any remaining defQueue items get properly processed.
1503 while (defQueue.length) {
1504 args = defQueue.shift();
1505 if (args[0] === null) {
1506 return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' +
1507 args[args.length - 1]));
1508 } else {
1509 //args are id, deps, factory. Should be normalized by the
1510 //define() function.
1511 callGetModule(args);
1512 }
1513 }
1514 context.defQueueMap = {};
1515 }
1516
1517 context = {
1518 config: config,
1519 contextName: contextName,
1520 registry: registry,
1521 defined: defined,
1522 urlFetched: urlFetched,
1523 defQueue: defQueue,
1524 defQueueMap: {},
1525 Module: Module,
1526 makeModuleMap: makeModuleMap,
1527 nextTick: req.nextTick,
1528 onError: onError,
1529
1530 /**
1531 * Set a configuration for the context.
1532 * @param {Object} cfg config object to integrate.
1533 */
1534 configure: function (cfg) {
1535 //Make sure the baseUrl ends in a slash.
1536 if (cfg.baseUrl) {
1537 if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
1538 cfg.baseUrl += '/';
1539 }
1540 }
1541
1542 //Save off the paths since they require special processing,
1543 //they are additive.
1544 var shim = config.shim,
1545 objs = {
1546 paths: true,
1547 bundles: true,
1548 config: true,
1549 map: true
1550 };
1551
1552 eachProp(cfg, function (value, prop) {
1553 if (objs[prop]) {
1554 if (!config[prop]) {
1555 config[prop] = {};
1556 }
1557 mixin(config[prop], value, true, true);
1558 } else {
1559 config[prop] = value;
1560 }
1561 });
1562
1563 //Reverse map the bundles
1564 if (cfg.bundles) {
1565 eachProp(cfg.bundles, function (value, prop) {
1566 each(value, function (v) {
1567 if (v !== prop) {
1568 bundlesMap[v] = prop;
1569 }
1570 });
1571 });
1572 }
1573
1574 //Merge shim
1575 if (cfg.shim) {
1576 eachProp(cfg.shim, function (value, id) {
1577 //Normalize the structure
1578 if (isArray(value)) {
1579 value = {
1580 deps: value
1581 };
1582 }
1583 if ((value.exports || value.init) && !value.exportsFn) {
1584 value.exportsFn = context.makeShimExports(value);
1585 }
1586 shim[id] = value;
1587 });
1588 config.shim = shim;
1589 }
1590
1591 //Adjust packages if necessary.
1592 if (cfg.packages) {
1593 each(cfg.packages, function (pkgObj) {
1594 var location, name;
1595
1596 pkgObj = typeof pkgObj === 'string' ? {name: pkgObj} : pkgObj;
1597
1598 name = pkgObj.name;
1599 location = pkgObj.location;
1600 if (location) {
1601 config.paths[name] = pkgObj.location;
1602 }
1603
1604 //Save pointer to main module ID for pkg name.
1605 //Remove leading dot in main, so main paths are normalized,
1606 //and remove any trailing .js, since different package
1607 //envs have different conventions: some use a module name,
1608 //some use a file name.
1609 config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
1610 .replace(currDirRegExp, '')
1611 .replace(jsSuffixRegExp, '');
1612 });
1613 }
1614
1615 //If there are any "waiting to execute" modules in the registry,
1616 //update the maps for them, since their info, like URLs to load,
1617 //may have changed.
1618 eachProp(registry, function (mod, id) {
1619 //If module already has init called, since it is too
1620 //late to modify them, and ignore unnormalized ones
1621 //since they are transient.
1622 if (!mod.inited && !mod.map.unnormalized) {
1623 mod.map = makeModuleMap(id, null, true);
1624 }
1625 });
1626
1627 //If a deps array or a config callback is specified, then call
1628 //require with those args. This is useful when require is defined as a
1629 //config object before require.js is loaded.
1630 if (cfg.deps || cfg.callback) {
1631 context.require(cfg.deps || [], cfg.callback);
1632 }
1633 },
1634
1635 makeShimExports: function (value) {
1636 function fn() {
1637 var ret;
1638 if (value.init) {
1639 ret = value.init.apply(global, arguments);
1640 }
1641 return ret || (value.exports && getGlobal(value.exports));
1642 }
1643 return fn;
1644 },
1645
1646 makeRequire: function (relMap, options) {
1647 options = options || {};
1648
1649 function localRequire(deps, callback, errback) {
1650 var id, map, requireMod;
1651
1652 if (options.enableBuildCallback && callback && isFunction(callback)) {
1653 callback.__requireJsBuild = true;
1654 }
1655
1656 if (typeof deps === 'string') {
1657 if (isFunction(callback)) {
1658 //Invalid call
1659 return onError(makeError('requireargs', 'Invalid require call'), errback);
1660 }
1661
1662 //If require|exports|module are requested, get the
1663 //value for them from the special handlers. Caveat:
1664 //this only works while module is being defined.
1665 if (relMap && hasProp(handlers, deps)) {
1666 return handlers[deps](registry[relMap.id]);
1667 }
1668
1669 //Synchronous access to one module. If require.get is
1670 //available (as in the Node adapter), prefer that.
1671 if (req.get) {
1672 return req.get(context, deps, relMap, localRequire);
1673 }
1674
1675 //Normalize module name, if it contains . or ..
1676 map = makeModuleMap(deps, relMap, false, true);
1677 id = map.id;
1678
1679 if (!hasProp(defined, id)) {
1680 return onError(makeError('notloaded', 'Module name "' +
1681 id +
1682 '" has not been loaded yet for context: ' +
1683 contextName +
1684 (relMap ? '' : '. Use require([])')));
1685 }
1686 return defined[id];
1687 }
1688
1689 //Grab defines waiting in the global queue.
1690 intakeDefines();
1691
1692 //Mark all the dependencies as needing to be loaded.
1693 context.nextTick(function () {
1694 //Some defines could have been added since the
1695 //require call, collect them.
1696 intakeDefines();
1697
1698 requireMod = getModule(makeModuleMap(null, relMap));
1699
1700 //Store if map config should be applied to this require
1701 //call for dependencies.
1702 requireMod.skipMap = options.skipMap;
1703
1704 requireMod.init(deps, callback, errback, {
1705 enabled: true
1706 });
1707
1708 checkLoaded();
1709 });
1710
1711 return localRequire;
1712 }
1713
1714 mixin(localRequire, {
1715 isBrowser: isBrowser,
1716
1717 /**
1718 * Converts a module name + .extension into an URL path.
1719 * *Requires* the use of a module name. It does not support using
1720 * plain URLs like nameToUrl.
1721 */
1722 toUrl: function (moduleNamePlusExt) {
1723 var ext,
1724 index = moduleNamePlusExt.lastIndexOf('.'),
1725 segment = moduleNamePlusExt.split('/')[0],
1726 isRelative = segment === '.' || segment === '..';
1727
1728 //Have a file extension alias, and it is not the
1729 //dots from a relative path.
1730 if (index !== -1 && (!isRelative || index > 1)) {
1731 ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
1732 moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
1733 }
1734
1735 return context.nameToUrl(normalize(moduleNamePlusExt,
1736 relMap && relMap.id, true), ext, true);
1737 },
1738
1739 defined: function (id) {
1740 return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
1741 },
1742
1743 specified: function (id) {
1744 id = makeModuleMap(id, relMap, false, true).id;
1745 return hasProp(defined, id) || hasProp(registry, id);
1746 }
1747 });
1748
1749 //Only allow undef on top level require calls
1750 if (!relMap) {
1751 localRequire.undef = function (id) {
1752 //Bind any waiting define() calls to this context,
1753 //fix for #408
1754 takeGlobalQueue();
1755
1756 var map = makeModuleMap(id, relMap, true),
1757 mod = getOwn(registry, id);
1758
1759 mod.undefed = true;
1760 removeScript(id);
1761
1762 delete defined[id];
1763 delete urlFetched[map.url];
1764 delete undefEvents[id];
1765
1766 //Clean queued defines too. Go backwards
1767 //in array so that the splices do not
1768 //mess up the iteration.
1769 eachReverse(defQueue, function(args, i) {
1770 if (args[0] === id) {
1771 defQueue.splice(i, 1);
1772 }
1773 });
1774 delete context.defQueueMap[id];
1775
1776 if (mod) {
1777 //Hold on to listeners in case the
1778 //module will be attempted to be reloaded
1779 //using a different config.
1780 if (mod.events.defined) {
1781 undefEvents[id] = mod.events;
1782 }
1783
1784 cleanRegistry(id);
1785 }
1786 };
1787 }
1788
1789 return localRequire;
1790 },
1791
1792 /**
1793 * Called to enable a module if it is still in the registry
1794 * awaiting enablement. A second arg, parent, the parent module,
1795 * is passed in for context, when this method is overridden by
1796 * the optimizer. Not shown here to keep code compact.
1797 */
1798 enable: function (depMap) {
1799 var mod = getOwn(registry, depMap.id);
1800 if (mod) {
1801 getModule(depMap).enable();
1802 }
1803 },
1804
1805 /**
1806 * Internal method used by environment adapters to complete a load event.
1807 * A load event could be a script load or just a load pass from a synchronous
1808 * load call.
1809 * @param {String} moduleName the name of the module to potentially complete.
1810 */
1811 completeLoad: function (moduleName) {
1812 var found, args, mod,
1813 shim = getOwn(config.shim, moduleName) || {},
1814 shExports = shim.exports;
1815
1816 takeGlobalQueue();
1817
1818 while (defQueue.length) {
1819 args = defQueue.shift();
1820 if (args[0] === null) {
1821 args[0] = moduleName;
1822 //If already found an anonymous module and bound it
1823 //to this name, then this is some other anon module
1824 //waiting for its completeLoad to fire.
1825 if (found) {
1826 break;
1827 }
1828 found = true;
1829 } else if (args[0] === moduleName) {
1830 //Found matching define call for this script!
1831 found = true;
1832 }
1833
1834 callGetModule(args);
1835 }
1836 context.defQueueMap = {};
1837
1838 //Do this after the cycle of callGetModule in case the result
1839 //of those calls/init calls changes the registry.
1840 mod = getOwn(registry, moduleName);
1841
1842 if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
1843 if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
1844 if (hasPathFallback(moduleName)) {
1845 return;
1846 } else {
1847 return onError(makeError('nodefine',
1848 'No define call for ' + moduleName,
1849 null,
1850 [moduleName]));
1851 }
1852 } else {
1853 //A script that does not call define(), so just simulate
1854 //the call for it.
1855 callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
1856 }
1857 }
1858
1859 checkLoaded();
1860 },
1861
1862 /**
1863 * Converts a module name to a file path. Supports cases where
1864 * moduleName may actually be just an URL.
1865 * Note that it **does not** call normalize on the moduleName,
1866 * it is assumed to have already been normalized. This is an
1867 * internal API, not a public one. Use toUrl for the public API.
1868 */
1869 nameToUrl: function (moduleName, ext, skipExt) {
1870 var paths, syms, i, parentModule, url,
1871 parentPath, bundleId,
1872 pkgMain = getOwn(config.pkgs, moduleName);
1873
1874 if (pkgMain) {
1875 moduleName = pkgMain;
1876 }
1877
1878 bundleId = getOwn(bundlesMap, moduleName);
1879
1880 if (bundleId) {
1881 return context.nameToUrl(bundleId, ext, skipExt);
1882 }
1883
1884 //If a colon is in the URL, it indicates a protocol is used and it is just
1885 //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
1886 //or ends with .js, then assume the user meant to use an url and not a module id.
1887 //The slash is important for protocol-less URLs as well as full paths.
1888 if (req.jsExtRegExp.test(moduleName)) {
1889 //Just a plain path, not module name lookup, so just return it.
1890 //Add extension if it is included. This is a bit wonky, only non-.js things pass
1891 //an extension, this method probably needs to be reworked.
1892 url = moduleName + (ext || '');
1893 } else {
1894 //A module that needs to be converted to a path.
1895 paths = config.paths;
1896
1897 syms = moduleName.split('/');
1898 //For each module name segment, see if there is a path
1899 //registered for it. Start with most specific name
1900 //and work up from it.
1901 for (i = syms.length; i > 0; i -= 1) {
1902 parentModule = syms.slice(0, i).join('/');
1903
1904 parentPath = getOwn(paths, parentModule);
1905 if (parentPath) {
1906 //If an array, it means there are a few choices,
1907 //Choose the one that is desired
1908 if (isArray(parentPath)) {
1909 parentPath = parentPath[0];
1910 }
1911 syms.splice(0, i, parentPath);
1912 break;
1913 }
1914 }
1915
1916 //Join the path parts together, then figure out if baseUrl is needed.
1917 url = syms.join('/');
1918 url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js'));
1919 url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
1920 }
1921
1922 return config.urlArgs ? url +
1923 ((url.indexOf('?') === -1 ? '?' : '&') +
1924 config.urlArgs) : url;
1925 },
1926
1927 //Delegates to req.load. Broken out as a separate function to
1928 //allow overriding in the optimizer.
1929 load: function (id, url) {
1930 req.load(context, id, url);
1931 },
1932
1933 /**
1934 * Executes a module callback function. Broken out as a separate function
1935 * solely to allow the build system to sequence the files in the built
1936 * layer in the right sequence.
1937 *
1938 * @private
1939 */
1940 execCb: function (name, callback, args, exports) {
1941 return callback.apply(exports, args);
1942 },
1943
1944 /**
1945 * callback for script loads, used to check status of loading.
1946 *
1947 * @param {Event} evt the event from the browser for the script
1948 * that was loaded.
1949 */
1950 onScriptLoad: function (evt) {
1951 //Using currentTarget instead of target for Firefox 2.0's sake. Not
1952 //all old browsers will be supported, but this one was easy enough
1953 //to support and still makes sense.
1954 if (evt.type === 'load' ||
1955 (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
1956 //Reset interactive script so a script node is not held onto for
1957 //to long.
1958 interactiveScript = null;
1959
1960 //Pull out the name of the module and the context.
1961 var data = getScriptData(evt);
1962 context.completeLoad(data.id);
1963 }
1964 },
1965
1966 /**
1967 * Callback for script errors.
1968 */
1969 onScriptError: function (evt) {
1970 var data = getScriptData(evt);
1971 if (!hasPathFallback(data.id)) {
1972 var parents = [];
1973 eachProp(registry, function(value, key) {
1974 if (key.indexOf('_@r') !== 0) {
1975 each(value.depMaps, function(depMap) {
1976 if (depMap.id === data.id) {
1977 parents.push(key);
1978 }
1979 return true;
1980 });
1981 }
1982 });
1983 return onError(makeError('scripterror', 'Script error for "' + data.id +
1984 (parents.length ?
1985 '", needed by: ' + parents.join(', ') :
1986 '"'), evt, [data.id]));
1987 }
1988 }
1989 };
1990
1991 context.require = context.makeRequire();
1992 return context;
1993 }
1994
1995 /**
1996 * Main entry point.
1997 *
1998 * If the only argument to require is a string, then the module that
1999 * is represented by that string is fetched for the appropriate context.
2000 *
2001 * If the first argument is an array, then it will be treated as an array
2002 * of dependency string names to fetch. An optional function callback can
2003 * be specified to execute when all of those dependencies are available.
2004 *
2005 * Make a local req variable to help Caja compliance (it assumes things
2006 * on a require that are not standardized), and to give a short
2007 * name for minification/local scope use.
2008 */
2009 req = requirejs = function (deps, callback, errback, optional) {
2010
2011 //Find the right context, use default
2012 var context, config,
2013 contextName = defContextName;
2014
2015 // Determine if have config object in the call.
2016 if (!isArray(deps) && typeof deps !== 'string') {
2017 // deps is a config object
2018 config = deps;
2019 if (isArray(callback)) {
2020 // Adjust args if there are dependencies
2021 deps = callback;
2022 callback = errback;
2023 errback = optional;
2024 } else {
2025 deps = [];
2026 }
2027 }
2028
2029 if (config && config.context) {
2030 contextName = config.context;
2031 }
2032
2033 context = getOwn(contexts, contextName);
2034 if (!context) {
2035 context = contexts[contextName] = req.s.newContext(contextName);
2036 }
2037
2038 if (config) {
2039 context.configure(config);
2040 }
2041
2042 return context.require(deps, callback, errback);
2043 };
2044
2045 /**
2046 * Support require.config() to make it easier to cooperate with other
2047 * AMD loaders on globally agreed names.
2048 */
2049 req.config = function (config) {
2050 return req(config);
2051 };
2052
2053 /**
2054 * Execute something after the current tick
2055 * of the event loop. Override for other envs
2056 * that have a better solution than setTimeout.
2057 * @param {Function} fn function to execute later.
2058 */
2059 req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
2060 setTimeout(fn, 4);
2061 } : function (fn) { fn(); };
2062
2063 /**
2064 * Export require as a global, but only if it does not already exist.
2065 */
2066 if (!require) {
2067 require = req;
2068 }
2069
2070 req.version = version;
2071
2072 //Used to filter out dependencies that are already paths.
2073 req.jsExtRegExp = /^\/|:|\?|\.js$/;
2074 req.isBrowser = isBrowser;
2075 s = req.s = {
2076 contexts: contexts,
2077 newContext: newContext
2078 };
2079
2080 //Create default context.
2081 req({});
2082
2083 //Exports some context-sensitive methods on global require.
2084 each([
2085 'toUrl',
2086 'undef',
2087 'defined',
2088 'specified'
2089 ], function (prop) {
2090 //Reference from contexts instead of early binding to default context,
2091 //so that during builds, the latest instance of the default context
2092 //with its config gets used.
2093 req[prop] = function () {
2094 var ctx = contexts[defContextName];
2095 return ctx.require[prop].apply(ctx, arguments);
2096 };
2097 });
2098
2099 if (isBrowser) {
2100 head = s.head = document.getElementsByTagName('head')[0];
2101 //If BASE tag is in play, using appendChild is a problem for IE6.
2102 //When that browser dies, this can be removed. Details in this jQuery bug:
2103 //http://dev.jquery.com/ticket/2709
2104 baseElement = document.getElementsByTagName('base')[0];
2105 if (baseElement) {
2106 head = s.head = baseElement.parentNode;
2107 }
2108 }
2109
2110 /**
2111 * Any errors that require explicitly generates will be passed to this
2112 * function. Intercept/override it if you want custom error handling.
2113 * @param {Error} err the error object.
2114 */
2115 req.onError = defaultOnError;
2116
2117 /**
2118 * Creates the node for the load command. Only used in browser envs.
2119 */
2120 req.createNode = function (config, moduleName, url) {
2121 var node = config.xhtml ?
2122 document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
2123 document.createElement('script');
2124 node.type = config.scriptType || 'text/javascript';
2125 node.charset = 'utf-8';
2126 node.async = true;
2127 return node;
2128 };
2129
2130 /**
2131 * Does the request to load a module for the browser case.
2132 * Make this a separate function to allow other environments
2133 * to override it.
2134 *
2135 * @param {Object} context the require context to find state.
2136 * @param {String} moduleName the name of the module.
2137 * @param {Object} url the URL to the module.
2138 */
2139 req.load = function (context, moduleName, url) {
2140 var config = (context && context.config) || {},
2141 node;
2142 if (isBrowser) {
2143 //In the browser so use a script tag
2144 node = req.createNode(config, moduleName, url);
2145 if (config.onNodeCreated) {
2146 config.onNodeCreated(node, config, moduleName, url);
2147 }
2148
2149 node.setAttribute('data-requirecontext', context.contextName);
2150 node.setAttribute('data-requiremodule', moduleName);
2151
2152 //Set up load listener. Test attachEvent first because IE9 has
2153 //a subtle issue in its addEventListener and script onload firings
2154 //that do not match the behavior of all other browsers with
2155 //addEventListener support, which fire the onload event for a
2156 //script right after the script execution. See:
2157 //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
2158 //UNFORTUNATELY Opera implements attachEvent but does not follow the script
2159 //script execution mode.
2160 if (node.attachEvent &&
2161 //Check if node.attachEvent is artificially added by custom script or
2162 //natively supported by browser
2163 //read https://github.com/jrburke/requirejs/issues/187
2164 //if we can NOT find [native code] then it must NOT natively supported.
2165 //in IE8, node.attachEvent does not have toString()
2166 //Note the test for "[native code" with no closing brace, see:
2167 //https://github.com/jrburke/requirejs/issues/273
2168 !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
2169 !isOpera) {
2170 //Probably IE. IE (at least 6-8) do not fire
2171 //script onload right after executing the script, so
2172 //we cannot tie the anonymous define call to a name.
2173 //However, IE reports the script as being in 'interactive'
2174 //readyState at the time of the define call.
2175 useInteractive = true;
2176
2177 node.attachEvent('onreadystatechange', context.onScriptLoad);
2178 //It would be great to add an error handler here to catch
2179 //404s in IE9+. However, onreadystatechange will fire before
2180 //the error handler, so that does not help. If addEventListener
2181 //is used, then IE will fire error before load, but we cannot
2182 //use that pathway given the connect.microsoft.com issue
2183 //mentioned above about not doing the 'script execute,
2184 //then fire the script load event listener before execute
2185 //next script' that other browsers do.
2186 //Best hope: IE10 fixes the issues,
2187 //and then destroys all installs of IE 6-9.
2188 //node.attachEvent('onerror', context.onScriptError);
2189 } else {
2190 node.addEventListener('load', context.onScriptLoad, false);
2191 node.addEventListener('error', context.onScriptError, false);
2192 }
2193 node.src = url;
2194
2195 //For some cache cases in IE 6-8, the script executes before the end
2196 //of the appendChild execution, so to tie an anonymous define
2197 //call to the module name (which is stored on the node), hold on
2198 //to a reference to this node, but clear after the DOM insertion.
2199 currentlyAddingScript = node;
2200 if (baseElement) {
2201 head.insertBefore(node, baseElement);
2202 } else {
2203 head.appendChild(node);
2204 }
2205 currentlyAddingScript = null;
2206
2207 return node;
2208 } else if (isWebWorker) {
2209 try {
2210 //In a web worker, use importScripts. This is not a very
2211 //efficient use of importScripts, importScripts will block until
2212 //its script is downloaded and evaluated. However, if web workers
2213 //are in play, the expectation is that a build has been done so
2214 //that only one script needs to be loaded anyway. This may need
2215 //to be reevaluated if other use cases become common.
2216 importScripts(url);
2217
2218 //Account for anonymous modules
2219 context.completeLoad(moduleName);
2220 } catch (e) {
2221 context.onError(makeError('importscripts',
2222 'importScripts failed for ' +
2223 moduleName + ' at ' + url,
2224 e,
2225 [moduleName]));
2226 }
2227 }
2228 };
2229
2230 function getInteractiveScript() {
2231 if (interactiveScript && interactiveScript.readyState === 'interactive') {
2232 return interactiveScript;
2233 }
2234
2235 eachReverse(scripts(), function (script) {
2236 if (script.readyState === 'interactive') {
2237 return (interactiveScript = script);
2238 }
2239 });
2240 return interactiveScript;
2241 }
2242
2243 //Look for a data-main script attribute, which could also adjust the baseUrl.
2244 if (isBrowser && !cfg.skipDataMain) {
2245 //Figure out baseUrl. Get it from the script tag with require.js in it.
2246 eachReverse(scripts(), function (script) {
2247 //Set the 'head' where we can append children by
2248 //using the script's parent.
2249 if (!head) {
2250 head = script.parentNode;
2251 }
2252
2253 //Look for a data-main attribute to set main script for the page
2254 //to load. If it is there, the path to data main becomes the
2255 //baseUrl, if it is not already set.
2256 dataMain = script.getAttribute('data-main');
2257 if (dataMain) {
2258 //Preserve dataMain in case it is a path (i.e. contains '?')
2259 mainScript = dataMain;
2260
2261 //Set final baseUrl if there is not already an explicit one.
2262 if (!cfg.baseUrl) {
2263 //Pull off the directory of data-main for use as the
2264 //baseUrl.
2265 src = mainScript.split('/');
2266 mainScript = src.pop();
2267 subPath = src.length ? src.join('/') + '/' : './';
2268
2269 cfg.baseUrl = subPath;
2270 }
2271
2272 //Strip off any trailing .js since mainScript is now
2273 //like a module name.
2274 mainScript = mainScript.replace(jsSuffixRegExp, '');
2275
2276 //If mainScript is still a path, fall back to dataMain
2277 if (req.jsExtRegExp.test(mainScript)) {
2278 mainScript = dataMain;
2279 }
2280
2281 //Put the data-main script in the files to load.
2282 cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
2283
2284 return true;
2285 }
2286 });
2287 }
2288
2289 /**
2290 * The function that handles definitions of modules. Differs from
2291 * require() in that a string for the module should be the first argument,
2292 * and the function to execute after dependencies are loaded should
2293 * return a value to define the module corresponding to the first argument's
2294 * name.
2295 */
2296 define = function (name, deps, callback) {
2297 var node, context;
2298
2299 //Allow for anonymous modules
2300 if (typeof name !== 'string') {
2301 //Adjust args appropriately
2302 callback = deps;
2303 deps = name;
2304 name = null;
2305 }
2306
2307 //This module may not have dependencies
2308 if (!isArray(deps)) {
2309 callback = deps;
2310 deps = null;
2311 }
2312
2313 //If no name, and callback is a function, then figure out if it a
2314 //CommonJS thing with dependencies.
2315 if (!deps && isFunction(callback)) {
2316 deps = [];
2317 //Remove comments from the callback string,
2318 //look for require calls, and pull them into the dependencies,
2319 //but only if there are function args.
2320 if (callback.length) {
2321 callback
2322 .toString()
2323 .replace(commentRegExp, '')
2324 .replace(cjsRequireRegExp, function (match, dep) {
2325 deps.push(dep);
2326 });
2327
2328 //May be a CommonJS thing even without require calls, but still
2329 //could use exports, and module. Avoid doing exports and module
2330 //work though if it just needs require.
2331 //REQUIRES the function to expect the CommonJS variables in the
2332 //order listed below.
2333 deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
2334 }
2335 }
2336
2337 //If in IE 6-8 and hit an anonymous define() call, do the interactive
2338 //work.
2339 if (useInteractive) {
2340 node = currentlyAddingScript || getInteractiveScript();
2341 if (node) {
2342 if (!name) {
2343 name = node.getAttribute('data-requiremodule');
2344 }
2345 context = contexts[node.getAttribute('data-requirecontext')];
2346 }
2347 }
2348
2349 //Always save off evaluating the def call until the script onload handler.
2350 //This allows multiple modules to be in a file without prematurely
2351 //tracing dependencies, and allows for anonymous module support,
2352 //where the module name is not known until the script onload event
2353 //occurs. If no context, use the global queue, and get it processed
2354 //in the onscript load callback.
2355 if (context) {
2356 context.defQueue.push([name, deps, callback]);
2357 context.defQueueMap[name] = true;
2358 } else {
2359 globalDefQueue.push([name, deps, callback]);
2360 }
2361 };
2362
2363 define.amd = {
2364 jQuery: true
2365 };
2366
2367 /**
2368 * Executes the text. Normally just uses eval, but can be modified
2369 * to use a better, environment-specific call. Only used for transpiling
2370 * loader plugins, not for plain JS modules.
2371 * @param {String} text the text to execute/evaluate.
2372 */
2373 req.exec = function (text) {
2374 /*jslint evil: true */
2375 return eval(text);
2376 };
2377
2378 //Set up with config info.
2379 req(cfg);
2380}(this));
2381
2382
2383
2384 this.requirejsVars = {
2385 require: require,
2386 requirejs: require,
2387 define: define
2388 };
2389
2390 if (env === 'browser') {
2391 /**
2392 * @license RequireJS rhino Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
2393 * Available via the MIT or new BSD license.
2394 * see: http://github.com/jrburke/requirejs for details
2395 */
2396
2397//sloppy since eval enclosed with use strict causes problems if the source
2398//text is not strict-compliant.
2399/*jslint sloppy: true, evil: true */
2400/*global require, XMLHttpRequest */
2401
2402(function () {
2403 // Separate function to avoid eval pollution, same with arguments use.
2404 function exec() {
2405 eval(arguments[0]);
2406 }
2407
2408 require.load = function (context, moduleName, url) {
2409 var xhr = new XMLHttpRequest();
2410
2411 xhr.open('GET', url, true);
2412 xhr.send();
2413
2414 xhr.onreadystatechange = function () {
2415 if (xhr.readyState === 4) {
2416 exec(xhr.responseText);
2417
2418 //Support anonymous modules.
2419 context.completeLoad(moduleName);
2420 }
2421 };
2422 };
2423}());
2424 } else if (env === 'rhino') {
2425 /**
2426 * @license RequireJS rhino Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2427 * Available via the MIT or new BSD license.
2428 * see: http://github.com/jrburke/requirejs for details
2429 */
2430
2431/*jslint */
2432/*global require: false, java: false, load: false */
2433
2434(function () {
2435 'use strict';
2436 require.load = function (context, moduleName, url) {
2437
2438 load(url);
2439
2440 //Support anonymous modules.
2441 context.completeLoad(moduleName);
2442 };
2443
2444}());
2445 } else if (env === 'node') {
2446 this.requirejsVars.nodeRequire = nodeRequire;
2447 require.nodeRequire = nodeRequire;
2448
2449 /**
2450 * @license RequireJS node Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2451 * Available via the MIT or new BSD license.
2452 * see: http://github.com/jrburke/requirejs for details
2453 */
2454
2455//Explicity not strict since this file contains an eval call, and do not want
2456//to enforce strict on code evaluated that way. See
2457//https://github.com/jrburke/r.js/issues/774
2458/*jslint regexp: false, sloppy: true*/
2459/*global require: false, define: false, requirejsVars: false, process: false */
2460
2461/**
2462 * This adapter assumes that x.js has loaded it and set up
2463 * some variables. This adapter just allows limited RequireJS
2464 * usage from within the requirejs directory. The general
2465 * node adapater is r.js.
2466 */
2467
2468(function () {
2469 var nodeReq = requirejsVars.nodeRequire,
2470 req = requirejsVars.require,
2471 def = requirejsVars.define,
2472 fs = nodeReq('fs'),
2473 path = nodeReq('path'),
2474 vm = nodeReq('vm'),
2475 //In Node 0.7+ existsSync is on fs.
2476 exists = fs.existsSync || path.existsSync,
2477 hasOwn = Object.prototype.hasOwnProperty;
2478
2479 function hasProp(obj, prop) {
2480 return hasOwn.call(obj, prop);
2481 }
2482
2483 function syncTick(fn) {
2484 fn();
2485 }
2486
2487 function makeError(message, moduleName) {
2488 var err = new Error(message);
2489 err.requireModules = [moduleName];
2490 return err;
2491 }
2492
2493 //Supply an implementation that allows synchronous get of a module.
2494 req.get = function (context, moduleName, relModuleMap, localRequire) {
2495 if (moduleName === "require" || moduleName === "exports" || moduleName === "module") {
2496 context.onError(makeError("Explicit require of " + moduleName + " is not allowed.", moduleName));
2497 }
2498
2499 var ret, oldTick,
2500 moduleMap = context.makeModuleMap(moduleName, relModuleMap, false, true);
2501
2502 //Normalize module name, if it contains . or ..
2503 moduleName = moduleMap.id;
2504
2505 if (hasProp(context.defined, moduleName)) {
2506 ret = context.defined[moduleName];
2507 } else {
2508 if (ret === undefined) {
2509 //Make sure nextTick for this type of call is sync-based.
2510 oldTick = context.nextTick;
2511 context.nextTick = syncTick;
2512 try {
2513 if (moduleMap.prefix) {
2514 //A plugin, call requirejs to handle it. Now that
2515 //nextTick is syncTick, the require will complete
2516 //synchronously.
2517 localRequire([moduleMap.originalName]);
2518
2519 //Now that plugin is loaded, can regenerate the moduleMap
2520 //to get the final, normalized ID.
2521 moduleMap = context.makeModuleMap(moduleMap.originalName, relModuleMap, false, true);
2522 moduleName = moduleMap.id;
2523 } else {
2524 //Try to dynamically fetch it.
2525 req.load(context, moduleName, moduleMap.url);
2526
2527 //Enable the module
2528 context.enable(moduleMap, relModuleMap);
2529 }
2530
2531 //Break any cycles by requiring it normally, but this will
2532 //finish synchronously
2533 context.require([moduleName]);
2534
2535 //The above calls are sync, so can do the next thing safely.
2536 ret = context.defined[moduleName];
2537 } finally {
2538 context.nextTick = oldTick;
2539 }
2540 }
2541 }
2542
2543 return ret;
2544 };
2545
2546 req.nextTick = function (fn) {
2547 process.nextTick(fn);
2548 };
2549
2550 //Add wrapper around the code so that it gets the requirejs
2551 //API instead of the Node API, and it is done lexically so
2552 //that it survives later execution.
2553 req.makeNodeWrapper = function (contents) {
2554 return '(function (require, requirejs, define) { ' +
2555 contents +
2556 '\n}(requirejsVars.require, requirejsVars.requirejs, requirejsVars.define));';
2557 };
2558
2559 req.load = function (context, moduleName, url) {
2560 var contents, err,
2561 config = context.config;
2562
2563 if (config.shim[moduleName] && (!config.suppress || !config.suppress.nodeShim)) {
2564 console.warn('Shim config not supported in Node, may or may not work. Detected ' +
2565 'for module: ' + moduleName);
2566 }
2567
2568 if (exists(url)) {
2569 contents = fs.readFileSync(url, 'utf8');
2570
2571 contents = req.makeNodeWrapper(contents);
2572 try {
2573 vm.runInThisContext(contents, fs.realpathSync(url));
2574 } catch (e) {
2575 err = new Error('Evaluating ' + url + ' as module "' +
2576 moduleName + '" failed with error: ' + e);
2577 err.originalError = e;
2578 err.moduleName = moduleName;
2579 err.requireModules = [moduleName];
2580 err.fileName = url;
2581 return context.onError(err);
2582 }
2583 } else {
2584 def(moduleName, function () {
2585 //Get the original name, since relative requires may be
2586 //resolved differently in node (issue #202). Also, if relative,
2587 //make it relative to the URL of the item requesting it
2588 //(issue #393)
2589 var dirName,
2590 map = hasProp(context.registry, moduleName) &&
2591 context.registry[moduleName].map,
2592 parentMap = map && map.parentMap,
2593 originalName = map && map.originalName;
2594
2595 if (originalName.charAt(0) === '.' && parentMap) {
2596 dirName = parentMap.url.split('/');
2597 dirName.pop();
2598 originalName = dirName.join('/') + '/' + originalName;
2599 }
2600
2601 try {
2602 return (context.config.nodeRequire || req.nodeRequire)(originalName);
2603 } catch (e) {
2604 err = new Error('Tried loading "' + moduleName + '" at ' +
2605 url + ' then tried node\'s require("' +
2606 originalName + '") and it failed ' +
2607 'with error: ' + e);
2608 err.originalError = e;
2609 err.moduleName = originalName;
2610 err.requireModules = [moduleName];
2611 throw err;
2612 }
2613 });
2614 }
2615
2616 //Support anonymous modules.
2617 context.completeLoad(moduleName);
2618 };
2619
2620 //Override to provide the function wrapper for define/require.
2621 req.exec = function (text) {
2622 /*jslint evil: true */
2623 text = req.makeNodeWrapper(text);
2624 return eval(text);
2625 };
2626}());
2627
2628 } else if (env === 'xpconnect') {
2629 /**
2630 * @license RequireJS xpconnect Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
2631 * Available via the MIT or new BSD license.
2632 * see: http://github.com/jrburke/requirejs for details
2633 */
2634
2635/*jslint */
2636/*global require, load */
2637
2638(function () {
2639 'use strict';
2640 require.load = function (context, moduleName, url) {
2641
2642 load(url);
2643
2644 //Support anonymous modules.
2645 context.completeLoad(moduleName);
2646 };
2647
2648}());
2649
2650 }
2651
2652 //Support a default file name to execute. Useful for hosted envs
2653 //like Joyent where it defaults to a server.js as the only executed
2654 //script. But only do it if this is not an optimization run.
2655 if (commandOption !== 'o' && (!fileName || !jsSuffixRegExp.test(fileName))) {
2656 fileName = 'main.js';
2657 }
2658
2659 /**
2660 * Loads the library files that can be used for the optimizer, or for other
2661 * tasks.
2662 */
2663 function loadLib() {
2664 /**
2665 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2666 * Available via the MIT or new BSD license.
2667 * see: http://github.com/jrburke/requirejs for details
2668 */
2669
2670/*jslint strict: false */
2671/*global Packages: false, process: false, window: false, navigator: false,
2672 document: false, define: false */
2673
2674/**
2675 * A plugin that modifies any /env/ path to be the right path based on
2676 * the host environment. Right now only works for Node, Rhino and browser.
2677 */
2678(function () {
2679 var pathRegExp = /(\/|^)env\/|\{env\}/,
2680 env = 'unknown';
2681
2682 if (typeof process !== 'undefined' && process.versions && !!process.versions.node) {
2683 env = 'node';
2684 } else if (typeof Packages !== 'undefined') {
2685 env = 'rhino';
2686 } else if ((typeof navigator !== 'undefined' && typeof document !== 'undefined') ||
2687 (typeof importScripts !== 'undefined' && typeof self !== 'undefined')) {
2688 env = 'browser';
2689 } else if (typeof Components !== 'undefined' && Components.classes && Components.interfaces) {
2690 env = 'xpconnect';
2691 }
2692
2693 define('env', {
2694 get: function () {
2695 return env;
2696 },
2697
2698 load: function (name, req, load, config) {
2699 //Allow override in the config.
2700 if (config.env) {
2701 env = config.env;
2702 }
2703
2704 name = name.replace(pathRegExp, function (match, prefix) {
2705 if (match.indexOf('{') === -1) {
2706 return prefix + env + '/';
2707 } else {
2708 return env;
2709 }
2710 });
2711
2712 req([name], function (mod) {
2713 load(mod);
2714 });
2715 }
2716 });
2717}());
2718/**
2719 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
2720 * Available via the MIT or new BSD license.
2721 * see: http://github.com/jrburke/requirejs for details
2722 */
2723
2724/*jslint plusplus: true */
2725/*global define, java */
2726
2727define('lang', function () {
2728 'use strict';
2729
2730 var lang, isJavaObj,
2731 hasOwn = Object.prototype.hasOwnProperty;
2732
2733 function hasProp(obj, prop) {
2734 return hasOwn.call(obj, prop);
2735 }
2736
2737 isJavaObj = function () {
2738 return false;
2739 };
2740
2741 //Rhino, but not Nashorn (detected by importPackage not existing)
2742 //Can have some strange foreign objects.
2743 if (typeof java !== 'undefined' && java.lang && java.lang.Object && typeof importPackage !== 'undefined') {
2744 isJavaObj = function (obj) {
2745 return obj instanceof java.lang.Object;
2746 };
2747 }
2748
2749 lang = {
2750 backSlashRegExp: /\\/g,
2751 ostring: Object.prototype.toString,
2752
2753 isArray: Array.isArray || function (it) {
2754 return lang.ostring.call(it) === "[object Array]";
2755 },
2756
2757 isFunction: function(it) {
2758 return lang.ostring.call(it) === "[object Function]";
2759 },
2760
2761 isRegExp: function(it) {
2762 return it && it instanceof RegExp;
2763 },
2764
2765 hasProp: hasProp,
2766
2767 //returns true if the object does not have an own property prop,
2768 //or if it does, it is a falsy value.
2769 falseProp: function (obj, prop) {
2770 return !hasProp(obj, prop) || !obj[prop];
2771 },
2772
2773 //gets own property value for given prop on object
2774 getOwn: function (obj, prop) {
2775 return hasProp(obj, prop) && obj[prop];
2776 },
2777
2778 _mixin: function(dest, source, override){
2779 var name;
2780 for (name in source) {
2781 if(source.hasOwnProperty(name) &&
2782 (override || !dest.hasOwnProperty(name))) {
2783 dest[name] = source[name];
2784 }
2785 }
2786
2787 return dest; // Object
2788 },
2789
2790 /**
2791 * mixin({}, obj1, obj2) is allowed. If the last argument is a boolean,
2792 * then the source objects properties are force copied over to dest.
2793 */
2794 mixin: function(dest){
2795 var parameters = Array.prototype.slice.call(arguments),
2796 override, i, l;
2797
2798 if (!dest) { dest = {}; }
2799
2800 if (parameters.length > 2 && typeof arguments[parameters.length-1] === 'boolean') {
2801 override = parameters.pop();
2802 }
2803
2804 for (i = 1, l = parameters.length; i < l; i++) {
2805 lang._mixin(dest, parameters[i], override);
2806 }
2807 return dest; // Object
2808 },
2809
2810 /**
2811 * Does a deep mix of source into dest, where source values override
2812 * dest values if a winner is needed.
2813 * @param {Object} dest destination object that receives the mixed
2814 * values.
2815 * @param {Object} source source object contributing properties to mix
2816 * in.
2817 * @return {[Object]} returns dest object with the modification.
2818 */
2819 deepMix: function(dest, source) {
2820 lang.eachProp(source, function (value, prop) {
2821 if (typeof value === 'object' && value &&
2822 !lang.isArray(value) && !lang.isFunction(value) &&
2823 !(value instanceof RegExp)) {
2824
2825 if (!dest[prop]) {
2826 dest[prop] = {};
2827 }
2828 lang.deepMix(dest[prop], value);
2829 } else {
2830 dest[prop] = value;
2831 }
2832 });
2833 return dest;
2834 },
2835
2836 /**
2837 * Does a type of deep copy. Do not give it anything fancy, best
2838 * for basic object copies of objects that also work well as
2839 * JSON-serialized things, or has properties pointing to functions.
2840 * For non-array/object values, just returns the same object.
2841 * @param {Object} obj copy properties from this object
2842 * @param {Object} [ignoredProps] optional object whose own properties
2843 * are keys that should be ignored.
2844 * @return {Object}
2845 */
2846 deeplikeCopy: function (obj, ignoredProps) {
2847 var type, result;
2848
2849 if (lang.isArray(obj)) {
2850 result = [];
2851 obj.forEach(function(value) {
2852 result.push(lang.deeplikeCopy(value, ignoredProps));
2853 });
2854 return result;
2855 }
2856
2857 type = typeof obj;
2858 if (obj === null || obj === undefined || type === 'boolean' ||
2859 type === 'string' || type === 'number' || lang.isFunction(obj) ||
2860 lang.isRegExp(obj)|| isJavaObj(obj)) {
2861 return obj;
2862 }
2863
2864 //Anything else is an object, hopefully.
2865 result = {};
2866 lang.eachProp(obj, function(value, key) {
2867 if (!ignoredProps || !hasProp(ignoredProps, key)) {
2868 result[key] = lang.deeplikeCopy(value, ignoredProps);
2869 }
2870 });
2871 return result;
2872 },
2873
2874 delegate: (function () {
2875 // boodman/crockford delegation w/ cornford optimization
2876 function TMP() {}
2877 return function (obj, props) {
2878 TMP.prototype = obj;
2879 var tmp = new TMP();
2880 TMP.prototype = null;
2881 if (props) {
2882 lang.mixin(tmp, props);
2883 }
2884 return tmp; // Object
2885 };
2886 }()),
2887
2888 /**
2889 * Helper function for iterating over an array. If the func returns
2890 * a true value, it will break out of the loop.
2891 */
2892 each: function each(ary, func) {
2893 if (ary) {
2894 var i;
2895 for (i = 0; i < ary.length; i += 1) {
2896 if (func(ary[i], i, ary)) {
2897 break;
2898 }
2899 }
2900 }
2901 },
2902
2903 /**
2904 * Cycles over properties in an object and calls a function for each
2905 * property value. If the function returns a truthy value, then the
2906 * iteration is stopped.
2907 */
2908 eachProp: function eachProp(obj, func) {
2909 var prop;
2910 for (prop in obj) {
2911 if (hasProp(obj, prop)) {
2912 if (func(obj[prop], prop)) {
2913 break;
2914 }
2915 }
2916 }
2917 },
2918
2919 //Similar to Function.prototype.bind, but the "this" object is specified
2920 //first, since it is easier to read/figure out what "this" will be.
2921 bind: function bind(obj, fn) {
2922 return function () {
2923 return fn.apply(obj, arguments);
2924 };
2925 },
2926
2927 //Escapes a content string to be be a string that has characters escaped
2928 //for inclusion as part of a JS string.
2929 jsEscape: function (content) {
2930 return content.replace(/(["'\\])/g, '\\$1')
2931 .replace(/[\f]/g, "\\f")
2932 .replace(/[\b]/g, "\\b")
2933 .replace(/[\n]/g, "\\n")
2934 .replace(/[\t]/g, "\\t")
2935 .replace(/[\r]/g, "\\r");
2936 }
2937 };
2938 return lang;
2939});
2940/**
2941 * prim 0.0.1 Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
2942 * Available via the MIT or new BSD license.
2943 * see: http://github.com/requirejs/prim for details
2944 */
2945
2946/*global setImmediate, process, setTimeout, define, module */
2947
2948//Set prime.hideResolutionConflict = true to allow "resolution-races"
2949//in promise-tests to pass.
2950//Since the goal of prim is to be a small impl for trusted code, it is
2951//more important to normally throw in this case so that we can find
2952//logic errors quicker.
2953
2954var prim;
2955(function () {
2956 'use strict';
2957 var op = Object.prototype,
2958 hasOwn = op.hasOwnProperty;
2959
2960 function hasProp(obj, prop) {
2961 return hasOwn.call(obj, prop);
2962 }
2963
2964 /**
2965 * Helper function for iterating over an array. If the func returns
2966 * a true value, it will break out of the loop.
2967 */
2968 function each(ary, func) {
2969 if (ary) {
2970 var i;
2971 for (i = 0; i < ary.length; i += 1) {
2972 if (ary[i]) {
2973 func(ary[i], i, ary);
2974 }
2975 }
2976 }
2977 }
2978
2979 function check(p) {
2980 if (hasProp(p, 'e') || hasProp(p, 'v')) {
2981 if (!prim.hideResolutionConflict) {
2982 throw new Error('Prim promise already resolved: ' +
2983 JSON.stringify(p));
2984 }
2985 return false;
2986 }
2987 return true;
2988 }
2989
2990 function notify(ary, value) {
2991 prim.nextTick(function () {
2992 each(ary, function (item) {
2993 item(value);
2994 });
2995 });
2996 }
2997
2998 prim = function prim() {
2999 var p,
3000 ok = [],
3001 fail = [];
3002
3003 return (p = {
3004 callback: function (yes, no) {
3005 if (no) {
3006 p.errback(no);
3007 }
3008
3009 if (hasProp(p, 'v')) {
3010 prim.nextTick(function () {
3011 yes(p.v);
3012 });
3013 } else {
3014 ok.push(yes);
3015 }
3016 },
3017
3018 errback: function (no) {
3019 if (hasProp(p, 'e')) {
3020 prim.nextTick(function () {
3021 no(p.e);
3022 });
3023 } else {
3024 fail.push(no);
3025 }
3026 },
3027
3028 finished: function () {
3029 return hasProp(p, 'e') || hasProp(p, 'v');
3030 },
3031
3032 rejected: function () {
3033 return hasProp(p, 'e');
3034 },
3035
3036 resolve: function (v) {
3037 if (check(p)) {
3038 p.v = v;
3039 notify(ok, v);
3040 }
3041 return p;
3042 },
3043 reject: function (e) {
3044 if (check(p)) {
3045 p.e = e;
3046 notify(fail, e);
3047 }
3048 return p;
3049 },
3050
3051 start: function (fn) {
3052 p.resolve();
3053 return p.promise.then(fn);
3054 },
3055
3056 promise: {
3057 then: function (yes, no) {
3058 var next = prim();
3059
3060 p.callback(function (v) {
3061 try {
3062 if (yes && typeof yes === 'function') {
3063 v = yes(v);
3064 }
3065
3066 if (v && v.then) {
3067 v.then(next.resolve, next.reject);
3068 } else {
3069 next.resolve(v);
3070 }
3071 } catch (e) {
3072 next.reject(e);
3073 }
3074 }, function (e) {
3075 var err;
3076
3077 try {
3078 if (!no || typeof no !== 'function') {
3079 next.reject(e);
3080 } else {
3081 err = no(e);
3082
3083 if (err && err.then) {
3084 err.then(next.resolve, next.reject);
3085 } else {
3086 next.resolve(err);
3087 }
3088 }
3089 } catch (e2) {
3090 next.reject(e2);
3091 }
3092 });
3093
3094 return next.promise;
3095 },
3096
3097 fail: function (no) {
3098 return p.promise.then(null, no);
3099 },
3100
3101 end: function () {
3102 p.errback(function (e) {
3103 throw e;
3104 });
3105 }
3106 }
3107 });
3108 };
3109
3110 prim.serial = function (ary) {
3111 var result = prim().resolve().promise;
3112 each(ary, function (item) {
3113 result = result.then(function () {
3114 return item();
3115 });
3116 });
3117 return result;
3118 };
3119
3120 prim.nextTick = typeof setImmediate === 'function' ? setImmediate :
3121 (typeof process !== 'undefined' && process.nextTick ?
3122 process.nextTick : (typeof setTimeout !== 'undefined' ?
3123 function (fn) {
3124 setTimeout(fn, 0);
3125 } : function (fn) {
3126 fn();
3127 }));
3128
3129 if (typeof define === 'function' && define.amd) {
3130 define('prim', function () { return prim; });
3131 } else if (typeof module !== 'undefined' && module.exports) {
3132 module.exports = prim;
3133 }
3134}());
3135if(env === 'browser') {
3136/**
3137 * @license RequireJS Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
3138 * Available via the MIT or new BSD license.
3139 * see: http://github.com/jrburke/requirejs for details
3140 */
3141
3142/*jslint strict: false */
3143/*global define: false, load: false */
3144
3145//Just a stub for use with uglify's consolidator.js
3146define('browser/assert', function () {
3147 return {};
3148});
3149
3150}
3151
3152if(env === 'node') {
3153/**
3154 * @license RequireJS Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
3155 * Available via the MIT or new BSD license.
3156 * see: http://github.com/jrburke/requirejs for details
3157 */
3158
3159/*jslint strict: false */
3160/*global define: false, load: false */
3161
3162//Needed so that rhino/assert can return a stub for uglify's consolidator.js
3163define('node/assert', ['assert'], function (assert) {
3164 return assert;
3165});
3166
3167}
3168
3169if(env === 'rhino') {
3170/**
3171 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3172 * Available via the MIT or new BSD license.
3173 * see: http://github.com/jrburke/requirejs for details
3174 */
3175
3176/*jslint strict: false */
3177/*global define: false, load: false */
3178
3179//Just a stub for use with uglify's consolidator.js
3180define('rhino/assert', function () {
3181 return {};
3182});
3183
3184}
3185
3186if(env === 'xpconnect') {
3187/**
3188 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3189 * Available via the MIT or new BSD license.
3190 * see: http://github.com/jrburke/requirejs for details
3191 */
3192
3193/*jslint strict: false */
3194/*global define: false, load: false */
3195
3196//Just a stub for use with uglify's consolidator.js
3197define('xpconnect/assert', function () {
3198 return {};
3199});
3200
3201}
3202
3203if(env === 'browser') {
3204/**
3205 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3206 * Available via the MIT or new BSD license.
3207 * see: http://github.com/jrburke/requirejs for details
3208 */
3209
3210/*jslint strict: false */
3211/*global define: false, process: false */
3212
3213define('browser/args', function () {
3214 //Always expect config via an API call
3215 return [];
3216});
3217
3218}
3219
3220if(env === 'node') {
3221/**
3222 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3223 * Available via the MIT or new BSD license.
3224 * see: http://github.com/jrburke/requirejs for details
3225 */
3226
3227/*jslint strict: false */
3228/*global define: false, process: false */
3229
3230define('node/args', function () {
3231 //Do not return the "node" or "r.js" arguments
3232 var args = process.argv.slice(2);
3233
3234 //Ignore any command option used for main x.js branching
3235 if (args[0] && args[0].indexOf('-') === 0) {
3236 args = args.slice(1);
3237 }
3238
3239 return args;
3240});
3241
3242}
3243
3244if(env === 'rhino') {
3245/**
3246 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3247 * Available via the MIT or new BSD license.
3248 * see: http://github.com/jrburke/requirejs for details
3249 */
3250
3251/*jslint strict: false */
3252/*global define: false, process: false */
3253
3254var jsLibRhinoArgs = (typeof rhinoArgs !== 'undefined' && rhinoArgs) || [].concat(Array.prototype.slice.call(arguments, 0));
3255
3256define('rhino/args', function () {
3257 var args = jsLibRhinoArgs;
3258
3259 //Ignore any command option used for main x.js branching
3260 if (args[0] && args[0].indexOf('-') === 0) {
3261 args = args.slice(1);
3262 }
3263
3264 return args;
3265});
3266
3267}
3268
3269if(env === 'xpconnect') {
3270/**
3271 * @license Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3272 * Available via the MIT or new BSD license.
3273 * see: http://github.com/jrburke/requirejs for details
3274 */
3275
3276/*jslint strict: false */
3277/*global define, xpconnectArgs */
3278
3279var jsLibXpConnectArgs = (typeof xpconnectArgs !== 'undefined' && xpconnectArgs) || [].concat(Array.prototype.slice.call(arguments, 0));
3280
3281define('xpconnect/args', function () {
3282 var args = jsLibXpConnectArgs;
3283
3284 //Ignore any command option used for main x.js branching
3285 if (args[0] && args[0].indexOf('-') === 0) {
3286 args = args.slice(1);
3287 }
3288
3289 return args;
3290});
3291
3292}
3293
3294if(env === 'browser') {
3295/**
3296 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3297 * Available via the MIT or new BSD license.
3298 * see: http://github.com/jrburke/requirejs for details
3299 */
3300
3301/*jslint strict: false */
3302/*global define: false, console: false */
3303
3304define('browser/load', ['./file'], function (file) {
3305 function load(fileName) {
3306 eval(file.readFile(fileName));
3307 }
3308
3309 return load;
3310});
3311
3312}
3313
3314if(env === 'node') {
3315/**
3316 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3317 * Available via the MIT or new BSD license.
3318 * see: http://github.com/jrburke/requirejs for details
3319 */
3320
3321/*jslint strict: false */
3322/*global define: false, console: false */
3323
3324define('node/load', ['fs'], function (fs) {
3325 function load(fileName) {
3326 var contents = fs.readFileSync(fileName, 'utf8');
3327 process.compile(contents, fileName);
3328 }
3329
3330 return load;
3331});
3332
3333}
3334
3335if(env === 'rhino') {
3336/**
3337 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3338 * Available via the MIT or new BSD license.
3339 * see: http://github.com/jrburke/requirejs for details
3340 */
3341
3342/*jslint strict: false */
3343/*global define: false, load: false */
3344
3345define('rhino/load', function () {
3346 return load;
3347});
3348
3349}
3350
3351if(env === 'xpconnect') {
3352/**
3353 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
3354 * Available via the MIT or new BSD license.
3355 * see: http://github.com/jrburke/requirejs for details
3356 */
3357
3358/*jslint strict: false */
3359/*global define: false, load: false */
3360
3361define('xpconnect/load', function () {
3362 return load;
3363});
3364
3365}
3366
3367if(env === 'browser') {
3368/**
3369 * @license Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
3370 * Available via the MIT or new BSD license.
3371 * see: http://github.com/jrburke/requirejs for details
3372 */
3373
3374/*jslint sloppy: true, nomen: true */
3375/*global require, define, console, XMLHttpRequest, requirejs, location */
3376
3377define('browser/file', ['prim'], function (prim) {
3378
3379 var file,
3380 currDirRegExp = /^\.(\/|$)/;
3381
3382 function frontSlash(path) {
3383 return path.replace(/\\/g, '/');
3384 }
3385
3386 function exists(path) {
3387 var status, xhr = new XMLHttpRequest();
3388
3389 //Oh yeah, that is right SYNC IO. Behold its glory
3390 //and horrible blocking behavior.
3391 xhr.open('HEAD', path, false);
3392 xhr.send();
3393 status = xhr.status;
3394
3395 return status === 200 || status === 304;
3396 }
3397
3398 function mkDir(dir) {
3399 console.log('mkDir is no-op in browser');
3400 }
3401
3402 function mkFullDir(dir) {
3403 console.log('mkFullDir is no-op in browser');
3404 }
3405
3406 file = {
3407 backSlashRegExp: /\\/g,
3408 exclusionRegExp: /^\./,
3409 getLineSeparator: function () {
3410 return '/';
3411 },
3412
3413 exists: function (fileName) {
3414 return exists(fileName);
3415 },
3416
3417 parent: function (fileName) {
3418 var parts = fileName.split('/');
3419 parts.pop();
3420 return parts.join('/');
3421 },
3422
3423 /**
3424 * Gets the absolute file path as a string, normalized
3425 * to using front slashes for path separators.
3426 * @param {String} fileName
3427 */
3428 absPath: function (fileName) {
3429 var dir;
3430 if (currDirRegExp.test(fileName)) {
3431 dir = frontSlash(location.href);
3432 if (dir.indexOf('/') !== -1) {
3433 dir = dir.split('/');
3434
3435 //Pull off protocol and host, just want
3436 //to allow paths (other build parts, like
3437 //require._isSupportedBuildUrl do not support
3438 //full URLs), but a full path from
3439 //the root.
3440 dir.splice(0, 3);
3441
3442 dir.pop();
3443 dir = '/' + dir.join('/');
3444 }
3445
3446 fileName = dir + fileName.substring(1);
3447 }
3448
3449 return fileName;
3450 },
3451
3452 normalize: function (fileName) {
3453 return fileName;
3454 },
3455
3456 isFile: function (path) {
3457 return true;
3458 },
3459
3460 isDirectory: function (path) {
3461 return false;
3462 },
3463
3464 getFilteredFileList: function (startDir, regExpFilters, makeUnixPaths) {
3465 console.log('file.getFilteredFileList is no-op in browser');
3466 },
3467
3468 copyDir: function (srcDir, destDir, regExpFilter, onlyCopyNew) {
3469 console.log('file.copyDir is no-op in browser');
3470
3471 },
3472
3473 copyFile: function (srcFileName, destFileName, onlyCopyNew) {
3474 console.log('file.copyFile is no-op in browser');
3475 },
3476
3477 /**
3478 * Renames a file. May fail if "to" already exists or is on another drive.
3479 */
3480 renameFile: function (from, to) {
3481 console.log('file.renameFile is no-op in browser');
3482 },
3483
3484 /**
3485 * Reads a *text* file.
3486 */
3487 readFile: function (path, encoding) {
3488 var xhr = new XMLHttpRequest();
3489
3490 //Oh yeah, that is right SYNC IO. Behold its glory
3491 //and horrible blocking behavior.
3492 xhr.open('GET', path, false);
3493 xhr.send();
3494
3495 return xhr.responseText;
3496 },
3497
3498 readFileAsync: function (path, encoding) {
3499 var xhr = new XMLHttpRequest(),
3500 d = prim();
3501
3502 xhr.open('GET', path, true);
3503 xhr.send();
3504
3505 xhr.onreadystatechange = function () {
3506 if (xhr.readyState === 4) {
3507 if (xhr.status > 400) {
3508 d.reject(new Error('Status: ' + xhr.status + ': ' + xhr.statusText));
3509 } else {
3510 d.resolve(xhr.responseText);
3511 }
3512 }
3513 };
3514
3515 return d.promise;
3516 },
3517
3518 saveUtf8File: function (fileName, fileContents) {
3519 //summary: saves a *text* file using UTF-8 encoding.
3520 file.saveFile(fileName, fileContents, "utf8");
3521 },
3522
3523 saveFile: function (fileName, fileContents, encoding) {
3524 requirejs.browser.saveFile(fileName, fileContents, encoding);
3525 },
3526
3527 deleteFile: function (fileName) {
3528 console.log('file.deleteFile is no-op in browser');
3529 },
3530
3531 /**
3532 * Deletes any empty directories under the given directory.
3533 */
3534 deleteEmptyDirs: function (startDir) {
3535 console.log('file.deleteEmptyDirs is no-op in browser');
3536 }
3537 };
3538
3539 return file;
3540
3541});
3542
3543}
3544
3545if(env === 'node') {
3546/**
3547 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3548 * Available via the MIT or new BSD license.
3549 * see: http://github.com/jrburke/requirejs for details
3550 */
3551
3552/*jslint plusplus: false, octal:false, strict: false */
3553/*global define: false, process: false */
3554
3555define('node/file', ['fs', 'path', 'prim'], function (fs, path, prim) {
3556
3557 var isWindows = process.platform === 'win32',
3558 windowsDriveRegExp = /^[a-zA-Z]\:\/$/,
3559 file;
3560
3561 function frontSlash(path) {
3562 return path.replace(/\\/g, '/');
3563 }
3564
3565 function exists(path) {
3566 if (isWindows && path.charAt(path.length - 1) === '/' &&
3567 path.charAt(path.length - 2) !== ':') {
3568 path = path.substring(0, path.length - 1);
3569 }
3570
3571 try {
3572 fs.statSync(path);
3573 return true;
3574 } catch (e) {
3575 return false;
3576 }
3577 }
3578
3579 function mkDir(dir) {
3580 if (!exists(dir) && (!isWindows || !windowsDriveRegExp.test(dir))) {
3581 fs.mkdirSync(dir, 511);
3582 }
3583 }
3584
3585 function mkFullDir(dir) {
3586 var parts = dir.split('/'),
3587 currDir = '',
3588 first = true;
3589
3590 parts.forEach(function (part) {
3591 //First part may be empty string if path starts with a slash.
3592 currDir += part + '/';
3593 first = false;
3594
3595 if (part) {
3596 mkDir(currDir);
3597 }
3598 });
3599 }
3600
3601 file = {
3602 backSlashRegExp: /\\/g,
3603 exclusionRegExp: /^\./,
3604 getLineSeparator: function () {
3605 return '/';
3606 },
3607
3608 exists: function (fileName) {
3609 return exists(fileName);
3610 },
3611
3612 parent: function (fileName) {
3613 var parts = fileName.split('/');
3614 parts.pop();
3615 return parts.join('/');
3616 },
3617
3618 /**
3619 * Gets the absolute file path as a string, normalized
3620 * to using front slashes for path separators.
3621 * @param {String} fileName
3622 */
3623 absPath: function (fileName) {
3624 return frontSlash(path.normalize(frontSlash(fs.realpathSync(fileName))));
3625 },
3626
3627 normalize: function (fileName) {
3628 return frontSlash(path.normalize(fileName));
3629 },
3630
3631 isFile: function (path) {
3632 return fs.statSync(path).isFile();
3633 },
3634
3635 isDirectory: function (path) {
3636 return fs.statSync(path).isDirectory();
3637 },
3638
3639 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths) {
3640 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
3641 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
3642 //and it will be treated as the "include" case.
3643 //Ignores files/directories that start with a period (.) unless exclusionRegExp
3644 //is set to another value.
3645 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
3646 i, stat, filePath, ok, dirFiles, fileName;
3647
3648 topDir = startDir;
3649
3650 regExpInclude = regExpFilters.include || regExpFilters;
3651 regExpExclude = regExpFilters.exclude || null;
3652
3653 if (file.exists(topDir)) {
3654 dirFileArray = fs.readdirSync(topDir);
3655 for (i = 0; i < dirFileArray.length; i++) {
3656 fileName = dirFileArray[i];
3657 filePath = path.join(topDir, fileName);
3658 stat = fs.statSync(filePath);
3659 if (stat.isFile()) {
3660 if (makeUnixPaths) {
3661 //Make sure we have a JS string.
3662 if (filePath.indexOf("/") === -1) {
3663 filePath = frontSlash(filePath);
3664 }
3665 }
3666
3667 ok = true;
3668 if (regExpInclude) {
3669 ok = filePath.match(regExpInclude);
3670 }
3671 if (ok && regExpExclude) {
3672 ok = !filePath.match(regExpExclude);
3673 }
3674
3675 if (ok && (!file.exclusionRegExp ||
3676 !file.exclusionRegExp.test(fileName))) {
3677 files.push(filePath);
3678 }
3679 } else if (stat.isDirectory() &&
3680 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileName))) {
3681 dirFiles = this.getFilteredFileList(filePath, regExpFilters, makeUnixPaths);
3682 files.push.apply(files, dirFiles);
3683 }
3684 }
3685 }
3686
3687 return files; //Array
3688 },
3689
3690 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
3691 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
3692 //file should be copied. Returns a list file name strings of the destinations that were copied.
3693 regExpFilter = regExpFilter || /\w/;
3694
3695 //Normalize th directory names, but keep front slashes.
3696 //path module on windows now returns backslashed paths.
3697 srcDir = frontSlash(path.normalize(srcDir));
3698 destDir = frontSlash(path.normalize(destDir));
3699
3700 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
3701 copiedFiles = [], i, srcFileName, destFileName;
3702
3703 for (i = 0; i < fileNames.length; i++) {
3704 srcFileName = fileNames[i];
3705 destFileName = srcFileName.replace(srcDir, destDir);
3706
3707 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
3708 copiedFiles.push(destFileName);
3709 }
3710 }
3711
3712 return copiedFiles.length ? copiedFiles : null; //Array or null
3713 },
3714
3715 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
3716 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
3717 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
3718 var parentDir;
3719
3720 //logger.trace("Src filename: " + srcFileName);
3721 //logger.trace("Dest filename: " + destFileName);
3722
3723 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
3724 //than dest.
3725 if (onlyCopyNew) {
3726 if (file.exists(destFileName) && fs.statSync(destFileName).mtime.getTime() >= fs.statSync(srcFileName).mtime.getTime()) {
3727 return false; //Boolean
3728 }
3729 }
3730
3731 //Make sure destination dir exists.
3732 parentDir = path.dirname(destFileName);
3733 if (!file.exists(parentDir)) {
3734 mkFullDir(parentDir);
3735 }
3736
3737 fs.writeFileSync(destFileName, fs.readFileSync(srcFileName, 'binary'), 'binary');
3738
3739 return true; //Boolean
3740 },
3741
3742 /**
3743 * Renames a file. May fail if "to" already exists or is on another drive.
3744 */
3745 renameFile: function (from, to) {
3746 return fs.renameSync(from, to);
3747 },
3748
3749 /**
3750 * Reads a *text* file.
3751 */
3752 readFile: function (/*String*/path, /*String?*/encoding) {
3753 if (encoding === 'utf-8') {
3754 encoding = 'utf8';
3755 }
3756 if (!encoding) {
3757 encoding = 'utf8';
3758 }
3759
3760 var text = fs.readFileSync(path, encoding);
3761
3762 //Hmm, would not expect to get A BOM, but it seems to happen,
3763 //remove it just in case.
3764 if (text.indexOf('\uFEFF') === 0) {
3765 text = text.substring(1, text.length);
3766 }
3767
3768 return text;
3769 },
3770
3771 readFileAsync: function (path, encoding) {
3772 var d = prim();
3773 try {
3774 d.resolve(file.readFile(path, encoding));
3775 } catch (e) {
3776 d.reject(e);
3777 }
3778 return d.promise;
3779 },
3780
3781 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
3782 //summary: saves a *text* file using UTF-8 encoding.
3783 file.saveFile(fileName, fileContents, "utf8");
3784 },
3785
3786 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
3787 //summary: saves a *text* file.
3788 var parentDir;
3789
3790 if (encoding === 'utf-8') {
3791 encoding = 'utf8';
3792 }
3793 if (!encoding) {
3794 encoding = 'utf8';
3795 }
3796
3797 //Make sure destination directories exist.
3798 parentDir = path.dirname(fileName);
3799 if (!file.exists(parentDir)) {
3800 mkFullDir(parentDir);
3801 }
3802
3803 fs.writeFileSync(fileName, fileContents, encoding);
3804 },
3805
3806 deleteFile: function (/*String*/fileName) {
3807 //summary: deletes a file or directory if it exists.
3808 var files, i, stat;
3809 if (file.exists(fileName)) {
3810 stat = fs.lstatSync(fileName);
3811 if (stat.isDirectory()) {
3812 files = fs.readdirSync(fileName);
3813 for (i = 0; i < files.length; i++) {
3814 this.deleteFile(path.join(fileName, files[i]));
3815 }
3816 fs.rmdirSync(fileName);
3817 } else {
3818 fs.unlinkSync(fileName);
3819 }
3820 }
3821 },
3822
3823
3824 /**
3825 * Deletes any empty directories under the given directory.
3826 */
3827 deleteEmptyDirs: function (startDir) {
3828 var dirFileArray, i, fileName, filePath, stat;
3829
3830 if (file.exists(startDir)) {
3831 dirFileArray = fs.readdirSync(startDir);
3832 for (i = 0; i < dirFileArray.length; i++) {
3833 fileName = dirFileArray[i];
3834 filePath = path.join(startDir, fileName);
3835 stat = fs.lstatSync(filePath);
3836 if (stat.isDirectory()) {
3837 file.deleteEmptyDirs(filePath);
3838 }
3839 }
3840
3841 //If directory is now empty, remove it.
3842 if (fs.readdirSync(startDir).length === 0) {
3843 file.deleteFile(startDir);
3844 }
3845 }
3846 }
3847 };
3848
3849 return file;
3850
3851});
3852
3853}
3854
3855if(env === 'rhino') {
3856/**
3857 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3858 * Available via the MIT or new BSD license.
3859 * see: http://github.com/jrburke/requirejs for details
3860 */
3861//Helper functions to deal with file I/O.
3862
3863/*jslint plusplus: false */
3864/*global java: false, define: false */
3865
3866define('rhino/file', ['prim'], function (prim) {
3867 var file = {
3868 backSlashRegExp: /\\/g,
3869
3870 exclusionRegExp: /^\./,
3871
3872 getLineSeparator: function () {
3873 return file.lineSeparator;
3874 },
3875
3876 lineSeparator: java.lang.System.getProperty("line.separator"), //Java String
3877
3878 exists: function (fileName) {
3879 return (new java.io.File(fileName)).exists();
3880 },
3881
3882 parent: function (fileName) {
3883 return file.absPath((new java.io.File(fileName)).getParentFile());
3884 },
3885
3886 normalize: function (fileName) {
3887 return file.absPath(fileName);
3888 },
3889
3890 isFile: function (path) {
3891 return (new java.io.File(path)).isFile();
3892 },
3893
3894 isDirectory: function (path) {
3895 return (new java.io.File(path)).isDirectory();
3896 },
3897
3898 /**
3899 * Gets the absolute file path as a string, normalized
3900 * to using front slashes for path separators.
3901 * @param {java.io.File||String} file
3902 */
3903 absPath: function (fileObj) {
3904 if (typeof fileObj === "string") {
3905 fileObj = new java.io.File(fileObj);
3906 }
3907 return (fileObj.getCanonicalPath() + "").replace(file.backSlashRegExp, "/");
3908 },
3909
3910 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) {
3911 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
3912 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
3913 //and it will be treated as the "include" case.
3914 //Ignores files/directories that start with a period (.) unless exclusionRegExp
3915 //is set to another value.
3916 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
3917 i, fileObj, filePath, ok, dirFiles;
3918
3919 topDir = startDir;
3920 if (!startDirIsJavaObject) {
3921 topDir = new java.io.File(startDir);
3922 }
3923
3924 regExpInclude = regExpFilters.include || regExpFilters;
3925 regExpExclude = regExpFilters.exclude || null;
3926
3927 if (topDir.exists()) {
3928 dirFileArray = topDir.listFiles();
3929 for (i = 0; i < dirFileArray.length; i++) {
3930 fileObj = dirFileArray[i];
3931 if (fileObj.isFile()) {
3932 filePath = fileObj.getPath();
3933 if (makeUnixPaths) {
3934 //Make sure we have a JS string.
3935 filePath = String(filePath);
3936 if (filePath.indexOf("/") === -1) {
3937 filePath = filePath.replace(/\\/g, "/");
3938 }
3939 }
3940
3941 ok = true;
3942 if (regExpInclude) {
3943 ok = filePath.match(regExpInclude);
3944 }
3945 if (ok && regExpExclude) {
3946 ok = !filePath.match(regExpExclude);
3947 }
3948
3949 if (ok && (!file.exclusionRegExp ||
3950 !file.exclusionRegExp.test(fileObj.getName()))) {
3951 files.push(filePath);
3952 }
3953 } else if (fileObj.isDirectory() &&
3954 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.getName()))) {
3955 dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true);
3956 files.push.apply(files, dirFiles);
3957 }
3958 }
3959 }
3960
3961 return files; //Array
3962 },
3963
3964 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
3965 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
3966 //file should be copied. Returns a list file name strings of the destinations that were copied.
3967 regExpFilter = regExpFilter || /\w/;
3968
3969 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
3970 copiedFiles = [], i, srcFileName, destFileName;
3971
3972 for (i = 0; i < fileNames.length; i++) {
3973 srcFileName = fileNames[i];
3974 destFileName = srcFileName.replace(srcDir, destDir);
3975
3976 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
3977 copiedFiles.push(destFileName);
3978 }
3979 }
3980
3981 return copiedFiles.length ? copiedFiles : null; //Array or null
3982 },
3983
3984 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
3985 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
3986 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
3987 var destFile = new java.io.File(destFileName), srcFile, parentDir,
3988 srcChannel, destChannel;
3989
3990 //logger.trace("Src filename: " + srcFileName);
3991 //logger.trace("Dest filename: " + destFileName);
3992
3993 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
3994 //than dest.
3995 if (onlyCopyNew) {
3996 srcFile = new java.io.File(srcFileName);
3997 if (destFile.exists() && destFile.lastModified() >= srcFile.lastModified()) {
3998 return false; //Boolean
3999 }
4000 }
4001
4002 //Make sure destination dir exists.
4003 parentDir = destFile.getParentFile();
4004 if (!parentDir.exists()) {
4005 if (!parentDir.mkdirs()) {
4006 throw "Could not create directory: " + parentDir.getCanonicalPath();
4007 }
4008 }
4009
4010 //Java's version of copy file.
4011 srcChannel = new java.io.FileInputStream(srcFileName).getChannel();
4012 destChannel = new java.io.FileOutputStream(destFileName).getChannel();
4013 destChannel.transferFrom(srcChannel, 0, srcChannel.size());
4014 srcChannel.close();
4015 destChannel.close();
4016
4017 return true; //Boolean
4018 },
4019
4020 /**
4021 * Renames a file. May fail if "to" already exists or is on another drive.
4022 */
4023 renameFile: function (from, to) {
4024 return (new java.io.File(from)).renameTo((new java.io.File(to)));
4025 },
4026
4027 readFile: function (/*String*/path, /*String?*/encoding) {
4028 //A file read function that can deal with BOMs
4029 encoding = encoding || "utf-8";
4030 var fileObj = new java.io.File(path),
4031 input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(fileObj), encoding)),
4032 stringBuffer, line;
4033 try {
4034 stringBuffer = new java.lang.StringBuffer();
4035 line = input.readLine();
4036
4037 // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
4038 // http://www.unicode.org/faq/utf_bom.html
4039
4040 // 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:
4041 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
4042 if (line && line.length() && line.charAt(0) === 0xfeff) {
4043 // Eat the BOM, since we've already found the encoding on this file,
4044 // and we plan to concatenating this buffer with others; the BOM should
4045 // only appear at the top of a file.
4046 line = line.substring(1);
4047 }
4048 while (line !== null) {
4049 stringBuffer.append(line);
4050 stringBuffer.append(file.lineSeparator);
4051 line = input.readLine();
4052 }
4053 //Make sure we return a JavaScript string and not a Java string.
4054 return String(stringBuffer.toString()); //String
4055 } finally {
4056 input.close();
4057 }
4058 },
4059
4060 readFileAsync: function (path, encoding) {
4061 var d = prim();
4062 try {
4063 d.resolve(file.readFile(path, encoding));
4064 } catch (e) {
4065 d.reject(e);
4066 }
4067 return d.promise;
4068 },
4069
4070 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
4071 //summary: saves a file using UTF-8 encoding.
4072 file.saveFile(fileName, fileContents, "utf-8");
4073 },
4074
4075 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
4076 //summary: saves a file.
4077 var outFile = new java.io.File(fileName), outWriter, parentDir, os;
4078
4079 parentDir = outFile.getAbsoluteFile().getParentFile();
4080 if (!parentDir.exists()) {
4081 if (!parentDir.mkdirs()) {
4082 throw "Could not create directory: " + parentDir.getAbsolutePath();
4083 }
4084 }
4085
4086 if (encoding) {
4087 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
4088 } else {
4089 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
4090 }
4091
4092 os = new java.io.BufferedWriter(outWriter);
4093 try {
4094 //If in Nashorn, need to coerce the JS string to a Java string so that
4095 //writer.write method dispatch correctly detects the type.
4096 if (typeof importPackage !== 'undefined') {
4097 os.write(fileContents);
4098 } else {
4099 os.write(new java.lang.String(fileContents));
4100 }
4101 } finally {
4102 os.close();
4103 }
4104 },
4105
4106 deleteFile: function (/*String*/fileName) {
4107 //summary: deletes a file or directory if it exists.
4108 var fileObj = new java.io.File(fileName), files, i;
4109 if (fileObj.exists()) {
4110 if (fileObj.isDirectory()) {
4111 files = fileObj.listFiles();
4112 for (i = 0; i < files.length; i++) {
4113 this.deleteFile(files[i]);
4114 }
4115 }
4116 fileObj["delete"]();
4117 }
4118 },
4119
4120 /**
4121 * Deletes any empty directories under the given directory.
4122 * The startDirIsJavaObject is private to this implementation's
4123 * recursion needs.
4124 */
4125 deleteEmptyDirs: function (startDir, startDirIsJavaObject) {
4126 var topDir = startDir,
4127 dirFileArray, i, fileObj;
4128
4129 if (!startDirIsJavaObject) {
4130 topDir = new java.io.File(startDir);
4131 }
4132
4133 if (topDir.exists()) {
4134 dirFileArray = topDir.listFiles();
4135 for (i = 0; i < dirFileArray.length; i++) {
4136 fileObj = dirFileArray[i];
4137 if (fileObj.isDirectory()) {
4138 file.deleteEmptyDirs(fileObj, true);
4139 }
4140 }
4141
4142 //If the directory is empty now, delete it.
4143 if (topDir.listFiles().length === 0) {
4144 file.deleteFile(String(topDir.getPath()));
4145 }
4146 }
4147 }
4148 };
4149
4150 return file;
4151});
4152
4153}
4154
4155if(env === 'xpconnect') {
4156/**
4157 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
4158 * Available via the MIT or new BSD license.
4159 * see: http://github.com/jrburke/requirejs for details
4160 */
4161//Helper functions to deal with file I/O.
4162
4163/*jslint plusplus: false */
4164/*global define, Components, xpcUtil */
4165
4166define('xpconnect/file', ['prim'], function (prim) {
4167 var file,
4168 Cc = Components.classes,
4169 Ci = Components.interfaces,
4170 //Depends on xpcUtil which is set up in x.js
4171 xpfile = xpcUtil.xpfile;
4172
4173 function mkFullDir(dirObj) {
4174 //1 is DIRECTORY_TYPE, 511 is 0777 permissions
4175 if (!dirObj.exists()) {
4176 dirObj.create(1, 511);
4177 }
4178 }
4179
4180 file = {
4181 backSlashRegExp: /\\/g,
4182
4183 exclusionRegExp: /^\./,
4184
4185 getLineSeparator: function () {
4186 return file.lineSeparator;
4187 },
4188
4189 lineSeparator: ('@mozilla.org/windows-registry-key;1' in Cc) ?
4190 '\r\n' : '\n',
4191
4192 exists: function (fileName) {
4193 return xpfile(fileName).exists();
4194 },
4195
4196 parent: function (fileName) {
4197 return xpfile(fileName).parent;
4198 },
4199
4200 normalize: function (fileName) {
4201 return file.absPath(fileName);
4202 },
4203
4204 isFile: function (path) {
4205 return xpfile(path).isFile();
4206 },
4207
4208 isDirectory: function (path) {
4209 return xpfile(path).isDirectory();
4210 },
4211
4212 /**
4213 * Gets the absolute file path as a string, normalized
4214 * to using front slashes for path separators.
4215 * @param {java.io.File||String} file
4216 */
4217 absPath: function (fileObj) {
4218 if (typeof fileObj === "string") {
4219 fileObj = xpfile(fileObj);
4220 }
4221 return fileObj.path;
4222 },
4223
4224 getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsObject) {
4225 //summary: Recurses startDir and finds matches to the files that match regExpFilters.include
4226 //and do not match regExpFilters.exclude. Or just one regexp can be passed in for regExpFilters,
4227 //and it will be treated as the "include" case.
4228 //Ignores files/directories that start with a period (.) unless exclusionRegExp
4229 //is set to another value.
4230 var files = [], topDir, regExpInclude, regExpExclude, dirFileArray,
4231 fileObj, filePath, ok, dirFiles;
4232
4233 topDir = startDir;
4234 if (!startDirIsObject) {
4235 topDir = xpfile(startDir);
4236 }
4237
4238 regExpInclude = regExpFilters.include || regExpFilters;
4239 regExpExclude = regExpFilters.exclude || null;
4240
4241 if (topDir.exists()) {
4242 dirFileArray = topDir.directoryEntries;
4243 while (dirFileArray.hasMoreElements()) {
4244 fileObj = dirFileArray.getNext().QueryInterface(Ci.nsILocalFile);
4245 if (fileObj.isFile()) {
4246 filePath = fileObj.path;
4247 if (makeUnixPaths) {
4248 if (filePath.indexOf("/") === -1) {
4249 filePath = filePath.replace(/\\/g, "/");
4250 }
4251 }
4252
4253 ok = true;
4254 if (regExpInclude) {
4255 ok = filePath.match(regExpInclude);
4256 }
4257 if (ok && regExpExclude) {
4258 ok = !filePath.match(regExpExclude);
4259 }
4260
4261 if (ok && (!file.exclusionRegExp ||
4262 !file.exclusionRegExp.test(fileObj.leafName))) {
4263 files.push(filePath);
4264 }
4265 } else if (fileObj.isDirectory() &&
4266 (!file.exclusionRegExp || !file.exclusionRegExp.test(fileObj.leafName))) {
4267 dirFiles = this.getFilteredFileList(fileObj, regExpFilters, makeUnixPaths, true);
4268 files.push.apply(files, dirFiles);
4269 }
4270 }
4271 }
4272
4273 return files; //Array
4274 },
4275
4276 copyDir: function (/*String*/srcDir, /*String*/destDir, /*RegExp?*/regExpFilter, /*boolean?*/onlyCopyNew) {
4277 //summary: copies files from srcDir to destDir using the regExpFilter to determine if the
4278 //file should be copied. Returns a list file name strings of the destinations that were copied.
4279 regExpFilter = regExpFilter || /\w/;
4280
4281 var fileNames = file.getFilteredFileList(srcDir, regExpFilter, true),
4282 copiedFiles = [], i, srcFileName, destFileName;
4283
4284 for (i = 0; i < fileNames.length; i += 1) {
4285 srcFileName = fileNames[i];
4286 destFileName = srcFileName.replace(srcDir, destDir);
4287
4288 if (file.copyFile(srcFileName, destFileName, onlyCopyNew)) {
4289 copiedFiles.push(destFileName);
4290 }
4291 }
4292
4293 return copiedFiles.length ? copiedFiles : null; //Array or null
4294 },
4295
4296 copyFile: function (/*String*/srcFileName, /*String*/destFileName, /*boolean?*/onlyCopyNew) {
4297 //summary: copies srcFileName to destFileName. If onlyCopyNew is set, it only copies the file if
4298 //srcFileName is newer than destFileName. Returns a boolean indicating if the copy occurred.
4299 var destFile = xpfile(destFileName),
4300 srcFile = xpfile(srcFileName);
4301
4302 //logger.trace("Src filename: " + srcFileName);
4303 //logger.trace("Dest filename: " + destFileName);
4304
4305 //If onlyCopyNew is true, then compare dates and only copy if the src is newer
4306 //than dest.
4307 if (onlyCopyNew) {
4308 if (destFile.exists() && destFile.lastModifiedTime >= srcFile.lastModifiedTime) {
4309 return false; //Boolean
4310 }
4311 }
4312
4313 srcFile.copyTo(destFile.parent, destFile.leafName);
4314
4315 return true; //Boolean
4316 },
4317
4318 /**
4319 * Renames a file. May fail if "to" already exists or is on another drive.
4320 */
4321 renameFile: function (from, to) {
4322 var toFile = xpfile(to);
4323 return xpfile(from).moveTo(toFile.parent, toFile.leafName);
4324 },
4325
4326 readFile: xpcUtil.readFile,
4327
4328 readFileAsync: function (path, encoding) {
4329 var d = prim();
4330 try {
4331 d.resolve(file.readFile(path, encoding));
4332 } catch (e) {
4333 d.reject(e);
4334 }
4335 return d.promise;
4336 },
4337
4338 saveUtf8File: function (/*String*/fileName, /*String*/fileContents) {
4339 //summary: saves a file using UTF-8 encoding.
4340 file.saveFile(fileName, fileContents, "utf-8");
4341 },
4342
4343 saveFile: function (/*String*/fileName, /*String*/fileContents, /*String?*/encoding) {
4344 var outStream, convertStream,
4345 fileObj = xpfile(fileName);
4346
4347 mkFullDir(fileObj.parent);
4348
4349 try {
4350 outStream = Cc['@mozilla.org/network/file-output-stream;1']
4351 .createInstance(Ci.nsIFileOutputStream);
4352 //438 is decimal for 0777
4353 outStream.init(fileObj, 0x02 | 0x08 | 0x20, 511, 0);
4354
4355 convertStream = Cc['@mozilla.org/intl/converter-output-stream;1']
4356 .createInstance(Ci.nsIConverterOutputStream);
4357
4358 convertStream.init(outStream, encoding, 0, 0);
4359 convertStream.writeString(fileContents);
4360 } catch (e) {
4361 throw new Error((fileObj && fileObj.path || '') + ': ' + e);
4362 } finally {
4363 if (convertStream) {
4364 convertStream.close();
4365 }
4366 if (outStream) {
4367 outStream.close();
4368 }
4369 }
4370 },
4371
4372 deleteFile: function (/*String*/fileName) {
4373 //summary: deletes a file or directory if it exists.
4374 var fileObj = xpfile(fileName);
4375 if (fileObj.exists()) {
4376 fileObj.remove(true);
4377 }
4378 },
4379
4380 /**
4381 * Deletes any empty directories under the given directory.
4382 * The startDirIsJavaObject is private to this implementation's
4383 * recursion needs.
4384 */
4385 deleteEmptyDirs: function (startDir, startDirIsObject) {
4386 var topDir = startDir,
4387 dirFileArray, fileObj;
4388
4389 if (!startDirIsObject) {
4390 topDir = xpfile(startDir);
4391 }
4392
4393 if (topDir.exists()) {
4394 dirFileArray = topDir.directoryEntries;
4395 while (dirFileArray.hasMoreElements()) {
4396 fileObj = dirFileArray.getNext().QueryInterface(Ci.nsILocalFile);
4397
4398 if (fileObj.isDirectory()) {
4399 file.deleteEmptyDirs(fileObj, true);
4400 }
4401 }
4402
4403 //If the directory is empty now, delete it.
4404 dirFileArray = topDir.directoryEntries;
4405 if (!dirFileArray.hasMoreElements()) {
4406 file.deleteFile(topDir.path);
4407 }
4408 }
4409 }
4410 };
4411
4412 return file;
4413});
4414
4415}
4416
4417if(env === 'browser') {
4418/*global process */
4419define('browser/quit', function () {
4420 'use strict';
4421 return function (code) {
4422 };
4423});
4424}
4425
4426if(env === 'node') {
4427/*global process */
4428define('node/quit', function () {
4429 'use strict';
4430 return function (code) {
4431 var draining = 0;
4432 var exit = function () {
4433 if (draining === 0) {
4434 process.exit(code);
4435 } else {
4436 draining -= 1;
4437 }
4438 };
4439 if (process.stdout.bufferSize) {
4440 draining += 1;
4441 process.stdout.once('drain', exit);
4442 }
4443 if (process.stderr.bufferSize) {
4444 draining += 1;
4445 process.stderr.once('drain', exit);
4446 }
4447 exit();
4448 };
4449});
4450
4451}
4452
4453if(env === 'rhino') {
4454/*global quit */
4455define('rhino/quit', function () {
4456 'use strict';
4457 return function (code) {
4458 return quit(code);
4459 };
4460});
4461
4462}
4463
4464if(env === 'xpconnect') {
4465/*global quit */
4466define('xpconnect/quit', function () {
4467 'use strict';
4468 return function (code) {
4469 return quit(code);
4470 };
4471});
4472
4473}
4474
4475if(env === 'browser') {
4476/**
4477 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4478 * Available via the MIT or new BSD license.
4479 * see: http://github.com/jrburke/requirejs for details
4480 */
4481
4482/*jslint strict: false */
4483/*global define: false, console: false */
4484
4485define('browser/print', function () {
4486 function print(msg) {
4487 console.log(msg);
4488 }
4489
4490 return print;
4491});
4492
4493}
4494
4495if(env === 'node') {
4496/**
4497 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4498 * Available via the MIT or new BSD license.
4499 * see: http://github.com/jrburke/requirejs for details
4500 */
4501
4502/*jslint strict: false */
4503/*global define: false, console: false */
4504
4505define('node/print', function () {
4506 function print(msg) {
4507 console.log(msg);
4508 }
4509
4510 return print;
4511});
4512
4513}
4514
4515if(env === 'rhino') {
4516/**
4517 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4518 * Available via the MIT or new BSD license.
4519 * see: http://github.com/jrburke/requirejs for details
4520 */
4521
4522/*jslint strict: false */
4523/*global define: false, print: false */
4524
4525define('rhino/print', function () {
4526 return print;
4527});
4528
4529}
4530
4531if(env === 'xpconnect') {
4532/**
4533 * @license RequireJS Copyright (c) 2013-2014, The Dojo Foundation All Rights Reserved.
4534 * Available via the MIT or new BSD license.
4535 * see: http://github.com/jrburke/requirejs for details
4536 */
4537
4538/*jslint strict: false */
4539/*global define: false, print: false */
4540
4541define('xpconnect/print', function () {
4542 return print;
4543});
4544
4545}
4546/**
4547 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
4548 * Available via the MIT or new BSD license.
4549 * see: http://github.com/jrburke/requirejs for details
4550 */
4551
4552/*jslint nomen: false, strict: false */
4553/*global define: false */
4554
4555define('logger', ['env!env/print'], function (print) {
4556 var logger = {
4557 TRACE: 0,
4558 INFO: 1,
4559 WARN: 2,
4560 ERROR: 3,
4561 SILENT: 4,
4562 level: 0,
4563 logPrefix: "",
4564
4565 logLevel: function( level ) {
4566 this.level = level;
4567 },
4568
4569 trace: function (message) {
4570 if (this.level <= this.TRACE) {
4571 this._print(message);
4572 }
4573 },
4574
4575 info: function (message) {
4576 if (this.level <= this.INFO) {
4577 this._print(message);
4578 }
4579 },
4580
4581 warn: function (message) {
4582 if (this.level <= this.WARN) {
4583 this._print(message);
4584 }
4585 },
4586
4587 error: function (message) {
4588 if (this.level <= this.ERROR) {
4589 this._print(message);
4590 }
4591 },
4592
4593 _print: function (message) {
4594 this._sysPrint((this.logPrefix ? (this.logPrefix + " ") : "") + message);
4595 },
4596
4597 _sysPrint: function (message) {
4598 print(message);
4599 }
4600 };
4601
4602 return logger;
4603});
4604//Just a blank file to use when building the optimizer with the optimizer,
4605//so that the build does not attempt to inline some env modules,
4606//like Node's fs and path.
4607
4608/*
4609 Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved.
4610
4611 Redistribution and use in source and binary forms, with or without
4612 modification, are permitted provided that the following conditions are met:
4613
4614 * Redistributions of source code must retain the above copyright
4615 notice, this list of conditions and the following disclaimer.
4616 * Redistributions in binary form must reproduce the above copyright
4617 notice, this list of conditions and the following disclaimer in the
4618 documentation and/or other materials provided with the distribution.
4619
4620 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
4621 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4622 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4623 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
4624 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4625 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4626 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4627 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4628 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
4629 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4630*/
4631
4632(function (root, factory) {
4633 'use strict';
4634
4635 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
4636 // Rhino, and plain browser loading.
4637
4638 /* istanbul ignore next */
4639 if (typeof define === 'function' && define.amd) {
4640 define('esprima', ['exports'], factory);
4641 } else if (typeof exports !== 'undefined') {
4642 factory(exports);
4643 } else {
4644 factory((root.esprima = {}));
4645 }
4646}(this, function (exports) {
4647 'use strict';
4648
4649 var Token,
4650 TokenName,
4651 FnExprTokens,
4652 Syntax,
4653 PlaceHolders,
4654 Messages,
4655 Regex,
4656 source,
4657 strict,
4658 index,
4659 lineNumber,
4660 lineStart,
4661 hasLineTerminator,
4662 lastIndex,
4663 lastLineNumber,
4664 lastLineStart,
4665 startIndex,
4666 startLineNumber,
4667 startLineStart,
4668 scanning,
4669 length,
4670 lookahead,
4671 state,
4672 extra,
4673 isBindingElement,
4674 isAssignmentTarget,
4675 firstCoverInitializedNameError;
4676
4677 Token = {
4678 BooleanLiteral: 1,
4679 EOF: 2,
4680 Identifier: 3,
4681 Keyword: 4,
4682 NullLiteral: 5,
4683 NumericLiteral: 6,
4684 Punctuator: 7,
4685 StringLiteral: 8,
4686 RegularExpression: 9,
4687 Template: 10
4688 };
4689
4690 TokenName = {};
4691 TokenName[Token.BooleanLiteral] = 'Boolean';
4692 TokenName[Token.EOF] = '<end>';
4693 TokenName[Token.Identifier] = 'Identifier';
4694 TokenName[Token.Keyword] = 'Keyword';
4695 TokenName[Token.NullLiteral] = 'Null';
4696 TokenName[Token.NumericLiteral] = 'Numeric';
4697 TokenName[Token.Punctuator] = 'Punctuator';
4698 TokenName[Token.StringLiteral] = 'String';
4699 TokenName[Token.RegularExpression] = 'RegularExpression';
4700 TokenName[Token.Template] = 'Template';
4701
4702 // A function following one of those tokens is an expression.
4703 FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
4704 'return', 'case', 'delete', 'throw', 'void',
4705 // assignment operators
4706 '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
4707 '&=', '|=', '^=', ',',
4708 // binary/unary operators
4709 '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
4710 '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
4711 '<=', '<', '>', '!=', '!=='];
4712
4713 Syntax = {
4714 AssignmentExpression: 'AssignmentExpression',
4715 AssignmentPattern: 'AssignmentPattern',
4716 ArrayExpression: 'ArrayExpression',
4717 ArrayPattern: 'ArrayPattern',
4718 ArrowFunctionExpression: 'ArrowFunctionExpression',
4719 BlockStatement: 'BlockStatement',
4720 BinaryExpression: 'BinaryExpression',
4721 BreakStatement: 'BreakStatement',
4722 CallExpression: 'CallExpression',
4723 CatchClause: 'CatchClause',
4724 ClassBody: 'ClassBody',
4725 ClassDeclaration: 'ClassDeclaration',
4726 ClassExpression: 'ClassExpression',
4727 ConditionalExpression: 'ConditionalExpression',
4728 ContinueStatement: 'ContinueStatement',
4729 DoWhileStatement: 'DoWhileStatement',
4730 DebuggerStatement: 'DebuggerStatement',
4731 EmptyStatement: 'EmptyStatement',
4732 ExportAllDeclaration: 'ExportAllDeclaration',
4733 ExportDefaultDeclaration: 'ExportDefaultDeclaration',
4734 ExportNamedDeclaration: 'ExportNamedDeclaration',
4735 ExportSpecifier: 'ExportSpecifier',
4736 ExpressionStatement: 'ExpressionStatement',
4737 ForStatement: 'ForStatement',
4738 ForOfStatement: 'ForOfStatement',
4739 ForInStatement: 'ForInStatement',
4740 FunctionDeclaration: 'FunctionDeclaration',
4741 FunctionExpression: 'FunctionExpression',
4742 Identifier: 'Identifier',
4743 IfStatement: 'IfStatement',
4744 ImportDeclaration: 'ImportDeclaration',
4745 ImportDefaultSpecifier: 'ImportDefaultSpecifier',
4746 ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
4747 ImportSpecifier: 'ImportSpecifier',
4748 Literal: 'Literal',
4749 LabeledStatement: 'LabeledStatement',
4750 LogicalExpression: 'LogicalExpression',
4751 MemberExpression: 'MemberExpression',
4752 MetaProperty: 'MetaProperty',
4753 MethodDefinition: 'MethodDefinition',
4754 NewExpression: 'NewExpression',
4755 ObjectExpression: 'ObjectExpression',
4756 ObjectPattern: 'ObjectPattern',
4757 Program: 'Program',
4758 Property: 'Property',
4759 RestElement: 'RestElement',
4760 ReturnStatement: 'ReturnStatement',
4761 SequenceExpression: 'SequenceExpression',
4762 SpreadElement: 'SpreadElement',
4763 Super: 'Super',
4764 SwitchCase: 'SwitchCase',
4765 SwitchStatement: 'SwitchStatement',
4766 TaggedTemplateExpression: 'TaggedTemplateExpression',
4767 TemplateElement: 'TemplateElement',
4768 TemplateLiteral: 'TemplateLiteral',
4769 ThisExpression: 'ThisExpression',
4770 ThrowStatement: 'ThrowStatement',
4771 TryStatement: 'TryStatement',
4772 UnaryExpression: 'UnaryExpression',
4773 UpdateExpression: 'UpdateExpression',
4774 VariableDeclaration: 'VariableDeclaration',
4775 VariableDeclarator: 'VariableDeclarator',
4776 WhileStatement: 'WhileStatement',
4777 WithStatement: 'WithStatement',
4778 YieldExpression: 'YieldExpression'
4779 };
4780
4781 PlaceHolders = {
4782 ArrowParameterPlaceHolder: 'ArrowParameterPlaceHolder'
4783 };
4784
4785 // Error messages should be identical to V8.
4786 Messages = {
4787 UnexpectedToken: 'Unexpected token %0',
4788 UnexpectedNumber: 'Unexpected number',
4789 UnexpectedString: 'Unexpected string',
4790 UnexpectedIdentifier: 'Unexpected identifier',
4791 UnexpectedReserved: 'Unexpected reserved word',
4792 UnexpectedTemplate: 'Unexpected quasi %0',
4793 UnexpectedEOS: 'Unexpected end of input',
4794 NewlineAfterThrow: 'Illegal newline after throw',
4795 InvalidRegExp: 'Invalid regular expression',
4796 UnterminatedRegExp: 'Invalid regular expression: missing /',
4797 InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
4798 InvalidLHSInForIn: 'Invalid left-hand side in for-in',
4799 InvalidLHSInForLoop: 'Invalid left-hand side in for-loop',
4800 MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
4801 NoCatchOrFinally: 'Missing catch or finally after try',
4802 UnknownLabel: 'Undefined label \'%0\'',
4803 Redeclaration: '%0 \'%1\' has already been declared',
4804 IllegalContinue: 'Illegal continue statement',
4805 IllegalBreak: 'Illegal break statement',
4806 IllegalReturn: 'Illegal return statement',
4807 StrictModeWith: 'Strict mode code may not include a with statement',
4808 StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
4809 StrictVarName: 'Variable name may not be eval or arguments in strict mode',
4810 StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
4811 StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
4812 StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
4813 StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
4814 StrictDelete: 'Delete of an unqualified identifier in strict mode.',
4815 StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
4816 StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
4817 StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
4818 StrictReservedWord: 'Use of future reserved word in strict mode',
4819 TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
4820 ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
4821 DefaultRestParameter: 'Unexpected token =',
4822 ObjectPatternAsRestParameter: 'Unexpected token {',
4823 DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
4824 ConstructorSpecialMethod: 'Class constructor may not be an accessor',
4825 DuplicateConstructor: 'A class may only have one constructor',
4826 StaticPrototype: 'Classes may not have static property named prototype',
4827 MissingFromClause: 'Unexpected token',
4828 NoAsAfterImportNamespace: 'Unexpected token',
4829 InvalidModuleSpecifier: 'Unexpected token',
4830 IllegalImportDeclaration: 'Unexpected token',
4831 IllegalExportDeclaration: 'Unexpected token',
4832 DuplicateBinding: 'Duplicate binding %0'
4833 };
4834
4835 // See also tools/generate-unicode-regex.js.
4836 Regex = {
4837 // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierStart:
4838 NonAsciiIdentifierStart: /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\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-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\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-\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-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\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\u2118-\u211D\u2124\u2126\u2128\u212A-\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\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\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-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\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]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDE00-\uDE11\uDE13-\uDE2B\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDE00-\uDE2F\uDE44\uDE80-\uDEAA]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]/,
4839
4840 // ECMAScript 6/Unicode v7.0.0 NonAsciiIdentifierPart:
4841 NonAsciiIdentifierPart: /[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\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-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\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\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\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\u0D01-\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\u0DE6-\u0DEF\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\u1369-\u1371\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\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-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\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\u2118-\u211D\u2124\u2126\u2128\u212A-\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\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\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-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\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-\uFE2D\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]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDD0-\uDDDA\uDE00-\uDE11\uDE13-\uDE37\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF01-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/
4842 };
4843
4844 // Ensure the condition is true, otherwise throw an error.
4845 // This is only to have a better contract semantic, i.e. another safety net
4846 // to catch a logic error. The condition shall be fulfilled in normal case.
4847 // Do NOT use this to enforce a certain condition on any user input.
4848
4849 function assert(condition, message) {
4850 /* istanbul ignore if */
4851 if (!condition) {
4852 throw new Error('ASSERT: ' + message);
4853 }
4854 }
4855
4856 function isDecimalDigit(ch) {
4857 return (ch >= 0x30 && ch <= 0x39); // 0..9
4858 }
4859
4860 function isHexDigit(ch) {
4861 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
4862 }
4863
4864 function isOctalDigit(ch) {
4865 return '01234567'.indexOf(ch) >= 0;
4866 }
4867
4868 function octalToDecimal(ch) {
4869 // \0 is not octal escape sequence
4870 var octal = (ch !== '0'), code = '01234567'.indexOf(ch);
4871
4872 if (index < length && isOctalDigit(source[index])) {
4873 octal = true;
4874 code = code * 8 + '01234567'.indexOf(source[index++]);
4875
4876 // 3 digits are only allowed when string starts
4877 // with 0, 1, 2, 3
4878 if ('0123'.indexOf(ch) >= 0 &&
4879 index < length &&
4880 isOctalDigit(source[index])) {
4881 code = code * 8 + '01234567'.indexOf(source[index++]);
4882 }
4883 }
4884
4885 return {
4886 code: code,
4887 octal: octal
4888 };
4889 }
4890
4891 // ECMA-262 11.2 White Space
4892
4893 function isWhiteSpace(ch) {
4894 return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
4895 (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
4896 }
4897
4898 // ECMA-262 11.3 Line Terminators
4899
4900 function isLineTerminator(ch) {
4901 return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
4902 }
4903
4904 // ECMA-262 11.6 Identifier Names and Identifiers
4905
4906 function fromCodePoint(cp) {
4907 return (cp < 0x10000) ? String.fromCharCode(cp) :
4908 String.fromCharCode(0xD800 + ((cp - 0x10000) >> 10)) +
4909 String.fromCharCode(0xDC00 + ((cp - 0x10000) & 1023));
4910 }
4911
4912 function isIdentifierStart(ch) {
4913 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
4914 (ch >= 0x41 && ch <= 0x5A) || // A..Z
4915 (ch >= 0x61 && ch <= 0x7A) || // a..z
4916 (ch === 0x5C) || // \ (backslash)
4917 ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(fromCodePoint(ch)));
4918 }
4919
4920 function isIdentifierPart(ch) {
4921 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
4922 (ch >= 0x41 && ch <= 0x5A) || // A..Z
4923 (ch >= 0x61 && ch <= 0x7A) || // a..z
4924 (ch >= 0x30 && ch <= 0x39) || // 0..9
4925 (ch === 0x5C) || // \ (backslash)
4926 ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(fromCodePoint(ch)));
4927 }
4928
4929 // ECMA-262 11.6.2.2 Future Reserved Words
4930
4931 function isFutureReservedWord(id) {
4932 switch (id) {
4933 case 'enum':
4934 case 'export':
4935 case 'import':
4936 case 'super':
4937 return true;
4938 default:
4939 return false;
4940 }
4941 }
4942
4943 function isStrictModeReservedWord(id) {
4944 switch (id) {
4945 case 'implements':
4946 case 'interface':
4947 case 'package':
4948 case 'private':
4949 case 'protected':
4950 case 'public':
4951 case 'static':
4952 case 'yield':
4953 case 'let':
4954 return true;
4955 default:
4956 return false;
4957 }
4958 }
4959
4960 function isRestrictedWord(id) {
4961 return id === 'eval' || id === 'arguments';
4962 }
4963
4964 // ECMA-262 11.6.2.1 Keywords
4965
4966 function isKeyword(id) {
4967 switch (id.length) {
4968 case 2:
4969 return (id === 'if') || (id === 'in') || (id === 'do');
4970 case 3:
4971 return (id === 'var') || (id === 'for') || (id === 'new') ||
4972 (id === 'try') || (id === 'let');
4973 case 4:
4974 return (id === 'this') || (id === 'else') || (id === 'case') ||
4975 (id === 'void') || (id === 'with') || (id === 'enum');
4976 case 5:
4977 return (id === 'while') || (id === 'break') || (id === 'catch') ||
4978 (id === 'throw') || (id === 'const') || (id === 'yield') ||
4979 (id === 'class') || (id === 'super');
4980 case 6:
4981 return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
4982 (id === 'switch') || (id === 'export') || (id === 'import');
4983 case 7:
4984 return (id === 'default') || (id === 'finally') || (id === 'extends');
4985 case 8:
4986 return (id === 'function') || (id === 'continue') || (id === 'debugger');
4987 case 10:
4988 return (id === 'instanceof');
4989 default:
4990 return false;
4991 }
4992 }
4993
4994 // ECMA-262 11.4 Comments
4995
4996 function addComment(type, value, start, end, loc) {
4997 var comment;
4998
4999 assert(typeof start === 'number', 'Comment must have valid position');
5000
5001 state.lastCommentStart = start;
5002
5003 comment = {
5004 type: type,
5005 value: value
5006 };
5007 if (extra.range) {
5008 comment.range = [start, end];
5009 }
5010 if (extra.loc) {
5011 comment.loc = loc;
5012 }
5013 extra.comments.push(comment);
5014 if (extra.attachComment) {
5015 extra.leadingComments.push(comment);
5016 extra.trailingComments.push(comment);
5017 }
5018 if (extra.tokenize) {
5019 comment.type = comment.type + 'Comment';
5020 if (extra.delegate) {
5021 comment = extra.delegate(comment);
5022 }
5023 extra.tokens.push(comment);
5024 }
5025 }
5026
5027 function skipSingleLineComment(offset) {
5028 var start, loc, ch, comment;
5029
5030 start = index - offset;
5031 loc = {
5032 start: {
5033 line: lineNumber,
5034 column: index - lineStart - offset
5035 }
5036 };
5037
5038 while (index < length) {
5039 ch = source.charCodeAt(index);
5040 ++index;
5041 if (isLineTerminator(ch)) {
5042 hasLineTerminator = true;
5043 if (extra.comments) {
5044 comment = source.slice(start + offset, index - 1);
5045 loc.end = {
5046 line: lineNumber,
5047 column: index - lineStart - 1
5048 };
5049 addComment('Line', comment, start, index - 1, loc);
5050 }
5051 if (ch === 13 && source.charCodeAt(index) === 10) {
5052 ++index;
5053 }
5054 ++lineNumber;
5055 lineStart = index;
5056 return;
5057 }
5058 }
5059
5060 if (extra.comments) {
5061 comment = source.slice(start + offset, index);
5062 loc.end = {
5063 line: lineNumber,
5064 column: index - lineStart
5065 };
5066 addComment('Line', comment, start, index, loc);
5067 }
5068 }
5069
5070 function skipMultiLineComment() {
5071 var start, loc, ch, comment;
5072
5073 if (extra.comments) {
5074 start = index - 2;
5075 loc = {
5076 start: {
5077 line: lineNumber,
5078 column: index - lineStart - 2
5079 }
5080 };
5081 }
5082
5083 while (index < length) {
5084 ch = source.charCodeAt(index);
5085 if (isLineTerminator(ch)) {
5086 if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
5087 ++index;
5088 }
5089 hasLineTerminator = true;
5090 ++lineNumber;
5091 ++index;
5092 lineStart = index;
5093 } else if (ch === 0x2A) {
5094 // Block comment ends with '*/'.
5095 if (source.charCodeAt(index + 1) === 0x2F) {
5096 ++index;
5097 ++index;
5098 if (extra.comments) {
5099 comment = source.slice(start + 2, index - 2);
5100 loc.end = {
5101 line: lineNumber,
5102 column: index - lineStart
5103 };
5104 addComment('Block', comment, start, index, loc);
5105 }
5106 return;
5107 }
5108 ++index;
5109 } else {
5110 ++index;
5111 }
5112 }
5113
5114 // Ran off the end of the file - the whole thing is a comment
5115 if (extra.comments) {
5116 loc.end = {
5117 line: lineNumber,
5118 column: index - lineStart
5119 };
5120 comment = source.slice(start + 2, index);
5121 addComment('Block', comment, start, index, loc);
5122 }
5123 tolerateUnexpectedToken();
5124 }
5125
5126 function skipComment() {
5127 var ch, start;
5128 hasLineTerminator = false;
5129
5130 start = (index === 0);
5131 while (index < length) {
5132 ch = source.charCodeAt(index);
5133
5134 if (isWhiteSpace(ch)) {
5135 ++index;
5136 } else if (isLineTerminator(ch)) {
5137 hasLineTerminator = true;
5138 ++index;
5139 if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
5140 ++index;
5141 }
5142 ++lineNumber;
5143 lineStart = index;
5144 start = true;
5145 } else if (ch === 0x2F) { // U+002F is '/'
5146 ch = source.charCodeAt(index + 1);
5147 if (ch === 0x2F) {
5148 ++index;
5149 ++index;
5150 skipSingleLineComment(2);
5151 start = true;
5152 } else if (ch === 0x2A) { // U+002A is '*'
5153 ++index;
5154 ++index;
5155 skipMultiLineComment();
5156 } else {
5157 break;
5158 }
5159 } else if (start && ch === 0x2D) { // U+002D is '-'
5160 // U+003E is '>'
5161 if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
5162 // '-->' is a single-line comment
5163 index += 3;
5164 skipSingleLineComment(3);
5165 } else {
5166 break;
5167 }
5168 } else if (ch === 0x3C) { // U+003C is '<'
5169 if (source.slice(index + 1, index + 4) === '!--') {
5170 ++index; // `<`
5171 ++index; // `!`
5172 ++index; // `-`
5173 ++index; // `-`
5174 skipSingleLineComment(4);
5175 } else {
5176 break;
5177 }
5178 } else {
5179 break;
5180 }
5181 }
5182 }
5183
5184 function scanHexEscape(prefix) {
5185 var i, len, ch, code = 0;
5186
5187 len = (prefix === 'u') ? 4 : 2;
5188 for (i = 0; i < len; ++i) {
5189 if (index < length && isHexDigit(source[index])) {
5190 ch = source[index++];
5191 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
5192 } else {
5193 return '';
5194 }
5195 }
5196 return String.fromCharCode(code);
5197 }
5198
5199 function scanUnicodeCodePointEscape() {
5200 var ch, code;
5201
5202 ch = source[index];
5203 code = 0;
5204
5205 // At least, one hex digit is required.
5206 if (ch === '}') {
5207 throwUnexpectedToken();
5208 }
5209
5210 while (index < length) {
5211 ch = source[index++];
5212 if (!isHexDigit(ch)) {
5213 break;
5214 }
5215 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
5216 }
5217
5218 if (code > 0x10FFFF || ch !== '}') {
5219 throwUnexpectedToken();
5220 }
5221
5222 return fromCodePoint(code);
5223 }
5224
5225 function codePointAt(i) {
5226 var cp, first, second;
5227
5228 cp = source.charCodeAt(i);
5229 if (cp >= 0xD800 && cp <= 0xDBFF) {
5230 second = source.charCodeAt(i + 1);
5231 if (second >= 0xDC00 && second <= 0xDFFF) {
5232 first = cp;
5233 cp = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
5234 }
5235 }
5236
5237 return cp;
5238 }
5239
5240 function getComplexIdentifier() {
5241 var cp, ch, id;
5242
5243 cp = codePointAt(index);
5244 id = fromCodePoint(cp);
5245 index += id.length;
5246
5247 // '\u' (U+005C, U+0075) denotes an escaped character.
5248 if (cp === 0x5C) {
5249 if (source.charCodeAt(index) !== 0x75) {
5250 throwUnexpectedToken();
5251 }
5252 ++index;
5253 if (source[index] === '{') {
5254 ++index;
5255 ch = scanUnicodeCodePointEscape();
5256 } else {
5257 ch = scanHexEscape('u');
5258 cp = ch.charCodeAt(0);
5259 if (!ch || ch === '\\' || !isIdentifierStart(cp)) {
5260 throwUnexpectedToken();
5261 }
5262 }
5263 id = ch;
5264 }
5265
5266 while (index < length) {
5267 cp = codePointAt(index);
5268 if (!isIdentifierPart(cp)) {
5269 break;
5270 }
5271 ch = fromCodePoint(cp);
5272 id += ch;
5273 index += ch.length;
5274
5275 // '\u' (U+005C, U+0075) denotes an escaped character.
5276 if (cp === 0x5C) {
5277 id = id.substr(0, id.length - 1);
5278 if (source.charCodeAt(index) !== 0x75) {
5279 throwUnexpectedToken();
5280 }
5281 ++index;
5282 if (source[index] === '{') {
5283 ++index;
5284 ch = scanUnicodeCodePointEscape();
5285 } else {
5286 ch = scanHexEscape('u');
5287 cp = ch.charCodeAt(0);
5288 if (!ch || ch === '\\' || !isIdentifierPart(cp)) {
5289 throwUnexpectedToken();
5290 }
5291 }
5292 id += ch;
5293 }
5294 }
5295
5296 return id;
5297 }
5298
5299 function getIdentifier() {
5300 var start, ch;
5301
5302 start = index++;
5303 while (index < length) {
5304 ch = source.charCodeAt(index);
5305 if (ch === 0x5C) {
5306 // Blackslash (U+005C) marks Unicode escape sequence.
5307 index = start;
5308 return getComplexIdentifier();
5309 } else if (ch >= 0xD800 && ch < 0xDFFF) {
5310 // Need to handle surrogate pairs.
5311 index = start;
5312 return getComplexIdentifier();
5313 }
5314 if (isIdentifierPart(ch)) {
5315 ++index;
5316 } else {
5317 break;
5318 }
5319 }
5320
5321 return source.slice(start, index);
5322 }
5323
5324 function scanIdentifier() {
5325 var start, id, type;
5326
5327 start = index;
5328
5329 // Backslash (U+005C) starts an escaped character.
5330 id = (source.charCodeAt(index) === 0x5C) ? getComplexIdentifier() : getIdentifier();
5331
5332 // There is no keyword or literal with only one character.
5333 // Thus, it must be an identifier.
5334 if (id.length === 1) {
5335 type = Token.Identifier;
5336 } else if (isKeyword(id)) {
5337 type = Token.Keyword;
5338 } else if (id === 'null') {
5339 type = Token.NullLiteral;
5340 } else if (id === 'true' || id === 'false') {
5341 type = Token.BooleanLiteral;
5342 } else {
5343 type = Token.Identifier;
5344 }
5345
5346 return {
5347 type: type,
5348 value: id,
5349 lineNumber: lineNumber,
5350 lineStart: lineStart,
5351 start: start,
5352 end: index
5353 };
5354 }
5355
5356
5357 // ECMA-262 11.7 Punctuators
5358
5359 function scanPunctuator() {
5360 var token, str;
5361
5362 token = {
5363 type: Token.Punctuator,
5364 value: '',
5365 lineNumber: lineNumber,
5366 lineStart: lineStart,
5367 start: index,
5368 end: index
5369 };
5370
5371 // Check for most common single-character punctuators.
5372 str = source[index];
5373 switch (str) {
5374
5375 case '(':
5376 if (extra.tokenize) {
5377 extra.openParenToken = extra.tokenValues.length;
5378 }
5379 ++index;
5380 break;
5381
5382 case '{':
5383 if (extra.tokenize) {
5384 extra.openCurlyToken = extra.tokenValues.length;
5385 }
5386 state.curlyStack.push('{');
5387 ++index;
5388 break;
5389
5390 case '.':
5391 ++index;
5392 if (source[index] === '.' && source[index + 1] === '.') {
5393 // Spread operator: ...
5394 index += 2;
5395 str = '...';
5396 }
5397 break;
5398
5399 case '}':
5400 ++index;
5401 state.curlyStack.pop();
5402 break;
5403 case ')':
5404 case ';':
5405 case ',':
5406 case '[':
5407 case ']':
5408 case ':':
5409 case '?':
5410 case '~':
5411 ++index;
5412 break;
5413
5414 default:
5415 // 4-character punctuator.
5416 str = source.substr(index, 4);
5417 if (str === '>>>=') {
5418 index += 4;
5419 } else {
5420
5421 // 3-character punctuators.
5422 str = str.substr(0, 3);
5423 if (str === '===' || str === '!==' || str === '>>>' ||
5424 str === '<<=' || str === '>>=') {
5425 index += 3;
5426 } else {
5427
5428 // 2-character punctuators.
5429 str = str.substr(0, 2);
5430 if (str === '&&' || str === '||' || str === '==' || str === '!=' ||
5431 str === '+=' || str === '-=' || str === '*=' || str === '/=' ||
5432 str === '++' || str === '--' || str === '<<' || str === '>>' ||
5433 str === '&=' || str === '|=' || str === '^=' || str === '%=' ||
5434 str === '<=' || str === '>=' || str === '=>') {
5435 index += 2;
5436 } else {
5437
5438 // 1-character punctuators.
5439 str = source[index];
5440 if ('<>=!+-*%&|^/'.indexOf(str) >= 0) {
5441 ++index;
5442 }
5443 }
5444 }
5445 }
5446 }
5447
5448 if (index === token.start) {
5449 throwUnexpectedToken();
5450 }
5451
5452 token.end = index;
5453 token.value = str;
5454 return token;
5455 }
5456
5457 // ECMA-262 11.8.3 Numeric Literals
5458
5459 function scanHexLiteral(start) {
5460 var number = '';
5461
5462 while (index < length) {
5463 if (!isHexDigit(source[index])) {
5464 break;
5465 }
5466 number += source[index++];
5467 }
5468
5469 if (number.length === 0) {
5470 throwUnexpectedToken();
5471 }
5472
5473 if (isIdentifierStart(source.charCodeAt(index))) {
5474 throwUnexpectedToken();
5475 }
5476
5477 return {
5478 type: Token.NumericLiteral,
5479 value: parseInt('0x' + number, 16),
5480 lineNumber: lineNumber,
5481 lineStart: lineStart,
5482 start: start,
5483 end: index
5484 };
5485 }
5486
5487 function scanBinaryLiteral(start) {
5488 var ch, number;
5489
5490 number = '';
5491
5492 while (index < length) {
5493 ch = source[index];
5494 if (ch !== '0' && ch !== '1') {
5495 break;
5496 }
5497 number += source[index++];
5498 }
5499
5500 if (number.length === 0) {
5501 // only 0b or 0B
5502 throwUnexpectedToken();
5503 }
5504
5505 if (index < length) {
5506 ch = source.charCodeAt(index);
5507 /* istanbul ignore else */
5508 if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
5509 throwUnexpectedToken();
5510 }
5511 }
5512
5513 return {
5514 type: Token.NumericLiteral,
5515 value: parseInt(number, 2),
5516 lineNumber: lineNumber,
5517 lineStart: lineStart,
5518 start: start,
5519 end: index
5520 };
5521 }
5522
5523 function scanOctalLiteral(prefix, start) {
5524 var number, octal;
5525
5526 if (isOctalDigit(prefix)) {
5527 octal = true;
5528 number = '0' + source[index++];
5529 } else {
5530 octal = false;
5531 ++index;
5532 number = '';
5533 }
5534
5535 while (index < length) {
5536 if (!isOctalDigit(source[index])) {
5537 break;
5538 }
5539 number += source[index++];
5540 }
5541
5542 if (!octal && number.length === 0) {
5543 // only 0o or 0O
5544 throwUnexpectedToken();
5545 }
5546
5547 if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
5548 throwUnexpectedToken();
5549 }
5550
5551 return {
5552 type: Token.NumericLiteral,
5553 value: parseInt(number, 8),
5554 octal: octal,
5555 lineNumber: lineNumber,
5556 lineStart: lineStart,
5557 start: start,
5558 end: index
5559 };
5560 }
5561
5562 function isImplicitOctalLiteral() {
5563 var i, ch;
5564
5565 // Implicit octal, unless there is a non-octal digit.
5566 // (Annex B.1.1 on Numeric Literals)
5567 for (i = index + 1; i < length; ++i) {
5568 ch = source[i];
5569 if (ch === '8' || ch === '9') {
5570 return false;
5571 }
5572 if (!isOctalDigit(ch)) {
5573 return true;
5574 }
5575 }
5576
5577 return true;
5578 }
5579
5580 function scanNumericLiteral() {
5581 var number, start, ch;
5582
5583 ch = source[index];
5584 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
5585 'Numeric literal must start with a decimal digit or a decimal point');
5586
5587 start = index;
5588 number = '';
5589 if (ch !== '.') {
5590 number = source[index++];
5591 ch = source[index];
5592
5593 // Hex number starts with '0x'.
5594 // Octal number starts with '0'.
5595 // Octal number in ES6 starts with '0o'.
5596 // Binary number in ES6 starts with '0b'.
5597 if (number === '0') {
5598 if (ch === 'x' || ch === 'X') {
5599 ++index;
5600 return scanHexLiteral(start);
5601 }
5602 if (ch === 'b' || ch === 'B') {
5603 ++index;
5604 return scanBinaryLiteral(start);
5605 }
5606 if (ch === 'o' || ch === 'O') {
5607 return scanOctalLiteral(ch, start);
5608 }
5609
5610 if (isOctalDigit(ch)) {
5611 if (isImplicitOctalLiteral()) {
5612 return scanOctalLiteral(ch, start);
5613 }
5614 }
5615 }
5616
5617 while (isDecimalDigit(source.charCodeAt(index))) {
5618 number += source[index++];
5619 }
5620 ch = source[index];
5621 }
5622
5623 if (ch === '.') {
5624 number += source[index++];
5625 while (isDecimalDigit(source.charCodeAt(index))) {
5626 number += source[index++];
5627 }
5628 ch = source[index];
5629 }
5630
5631 if (ch === 'e' || ch === 'E') {
5632 number += source[index++];
5633
5634 ch = source[index];
5635 if (ch === '+' || ch === '-') {
5636 number += source[index++];
5637 }
5638 if (isDecimalDigit(source.charCodeAt(index))) {
5639 while (isDecimalDigit(source.charCodeAt(index))) {
5640 number += source[index++];
5641 }
5642 } else {
5643 throwUnexpectedToken();
5644 }
5645 }
5646
5647 if (isIdentifierStart(source.charCodeAt(index))) {
5648 throwUnexpectedToken();
5649 }
5650
5651 return {
5652 type: Token.NumericLiteral,
5653 value: parseFloat(number),
5654 lineNumber: lineNumber,
5655 lineStart: lineStart,
5656 start: start,
5657 end: index
5658 };
5659 }
5660
5661 // ECMA-262 11.8.4 String Literals
5662
5663 function scanStringLiteral() {
5664 var str = '', quote, start, ch, unescaped, octToDec, octal = false;
5665
5666 quote = source[index];
5667 assert((quote === '\'' || quote === '"'),
5668 'String literal must starts with a quote');
5669
5670 start = index;
5671 ++index;
5672
5673 while (index < length) {
5674 ch = source[index++];
5675
5676 if (ch === quote) {
5677 quote = '';
5678 break;
5679 } else if (ch === '\\') {
5680 ch = source[index++];
5681 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
5682 switch (ch) {
5683 case 'u':
5684 case 'x':
5685 if (source[index] === '{') {
5686 ++index;
5687 str += scanUnicodeCodePointEscape();
5688 } else {
5689 unescaped = scanHexEscape(ch);
5690 if (!unescaped) {
5691 throw throwUnexpectedToken();
5692 }
5693 str += unescaped;
5694 }
5695 break;
5696 case 'n':
5697 str += '\n';
5698 break;
5699 case 'r':
5700 str += '\r';
5701 break;
5702 case 't':
5703 str += '\t';
5704 break;
5705 case 'b':
5706 str += '\b';
5707 break;
5708 case 'f':
5709 str += '\f';
5710 break;
5711 case 'v':
5712 str += '\x0B';
5713 break;
5714 case '8':
5715 case '9':
5716 str += ch;
5717 tolerateUnexpectedToken();
5718 break;
5719
5720 default:
5721 if (isOctalDigit(ch)) {
5722 octToDec = octalToDecimal(ch);
5723
5724 octal = octToDec.octal || octal;
5725 str += String.fromCharCode(octToDec.code);
5726 } else {
5727 str += ch;
5728 }
5729 break;
5730 }
5731 } else {
5732 ++lineNumber;
5733 if (ch === '\r' && source[index] === '\n') {
5734 ++index;
5735 }
5736 lineStart = index;
5737 }
5738 } else if (isLineTerminator(ch.charCodeAt(0))) {
5739 break;
5740 } else {
5741 str += ch;
5742 }
5743 }
5744
5745 if (quote !== '') {
5746 throwUnexpectedToken();
5747 }
5748
5749 return {
5750 type: Token.StringLiteral,
5751 value: str,
5752 octal: octal,
5753 lineNumber: startLineNumber,
5754 lineStart: startLineStart,
5755 start: start,
5756 end: index
5757 };
5758 }
5759
5760 // ECMA-262 11.8.6 Template Literal Lexical Components
5761
5762 function scanTemplate() {
5763 var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped;
5764
5765 terminated = false;
5766 tail = false;
5767 start = index;
5768 head = (source[index] === '`');
5769 rawOffset = 2;
5770
5771 ++index;
5772
5773 while (index < length) {
5774 ch = source[index++];
5775 if (ch === '`') {
5776 rawOffset = 1;
5777 tail = true;
5778 terminated = true;
5779 break;
5780 } else if (ch === '$') {
5781 if (source[index] === '{') {
5782 state.curlyStack.push('${');
5783 ++index;
5784 terminated = true;
5785 break;
5786 }
5787 cooked += ch;
5788 } else if (ch === '\\') {
5789 ch = source[index++];
5790 if (!isLineTerminator(ch.charCodeAt(0))) {
5791 switch (ch) {
5792 case 'n':
5793 cooked += '\n';
5794 break;
5795 case 'r':
5796 cooked += '\r';
5797 break;
5798 case 't':
5799 cooked += '\t';
5800 break;
5801 case 'u':
5802 case 'x':
5803 if (source[index] === '{') {
5804 ++index;
5805 cooked += scanUnicodeCodePointEscape();
5806 } else {
5807 restore = index;
5808 unescaped = scanHexEscape(ch);
5809 if (unescaped) {
5810 cooked += unescaped;
5811 } else {
5812 index = restore;
5813 cooked += ch;
5814 }
5815 }
5816 break;
5817 case 'b':
5818 cooked += '\b';
5819 break;
5820 case 'f':
5821 cooked += '\f';
5822 break;
5823 case 'v':
5824 cooked += '\v';
5825 break;
5826
5827 default:
5828 if (ch === '0') {
5829 if (isDecimalDigit(source.charCodeAt(index))) {
5830 // Illegal: \01 \02 and so on
5831 throwError(Messages.TemplateOctalLiteral);
5832 }
5833 cooked += '\0';
5834 } else if (isOctalDigit(ch)) {
5835 // Illegal: \1 \2
5836 throwError(Messages.TemplateOctalLiteral);
5837 } else {
5838 cooked += ch;
5839 }
5840 break;
5841 }
5842 } else {
5843 ++lineNumber;
5844 if (ch === '\r' && source[index] === '\n') {
5845 ++index;
5846 }
5847 lineStart = index;
5848 }
5849 } else if (isLineTerminator(ch.charCodeAt(0))) {
5850 ++lineNumber;
5851 if (ch === '\r' && source[index] === '\n') {
5852 ++index;
5853 }
5854 lineStart = index;
5855 cooked += '\n';
5856 } else {
5857 cooked += ch;
5858 }
5859 }
5860
5861 if (!terminated) {
5862 throwUnexpectedToken();
5863 }
5864
5865 if (!head) {
5866 state.curlyStack.pop();
5867 }
5868
5869 return {
5870 type: Token.Template,
5871 value: {
5872 cooked: cooked,
5873 raw: source.slice(start + 1, index - rawOffset)
5874 },
5875 head: head,
5876 tail: tail,
5877 lineNumber: lineNumber,
5878 lineStart: lineStart,
5879 start: start,
5880 end: index
5881 };
5882 }
5883
5884 // ECMA-262 11.8.5 Regular Expression Literals
5885
5886 function testRegExp(pattern, flags) {
5887 // The BMP character to use as a replacement for astral symbols when
5888 // translating an ES6 "u"-flagged pattern to an ES5-compatible
5889 // approximation.
5890 // Note: replacing with '\uFFFF' enables false positives in unlikely
5891 // scenarios. For example, `[\u{1044f}-\u{10440}]` is an invalid
5892 // pattern that would not be detected by this substitution.
5893 var astralSubstitute = '\uFFFF',
5894 tmp = pattern;
5895
5896 if (flags.indexOf('u') >= 0) {
5897 tmp = tmp
5898 // Replace every Unicode escape sequence with the equivalent
5899 // BMP character or a constant ASCII code point in the case of
5900 // astral symbols. (See the above note on `astralSubstitute`
5901 // for more information.)
5902 .replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g, function ($0, $1, $2) {
5903 var codePoint = parseInt($1 || $2, 16);
5904 if (codePoint > 0x10FFFF) {
5905 throwUnexpectedToken(null, Messages.InvalidRegExp);
5906 }
5907 if (codePoint <= 0xFFFF) {
5908 return String.fromCharCode(codePoint);
5909 }
5910 return astralSubstitute;
5911 })
5912 // Replace each paired surrogate with a single ASCII symbol to
5913 // avoid throwing on regular expressions that are only valid in
5914 // combination with the "u" flag.
5915 .replace(
5916 /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
5917 astralSubstitute
5918 );
5919 }
5920
5921 // First, detect invalid regular expressions.
5922 try {
5923 RegExp(tmp);
5924 } catch (e) {
5925 throwUnexpectedToken(null, Messages.InvalidRegExp);
5926 }
5927
5928 // Return a regular expression object for this pattern-flag pair, or
5929 // `null` in case the current environment doesn't support the flags it
5930 // uses.
5931 try {
5932 return new RegExp(pattern, flags);
5933 } catch (exception) {
5934 return null;
5935 }
5936 }
5937
5938 function scanRegExpBody() {
5939 var ch, str, classMarker, terminated, body;
5940
5941 ch = source[index];
5942 assert(ch === '/', 'Regular expression literal must start with a slash');
5943 str = source[index++];
5944
5945 classMarker = false;
5946 terminated = false;
5947 while (index < length) {
5948 ch = source[index++];
5949 str += ch;
5950 if (ch === '\\') {
5951 ch = source[index++];
5952 // ECMA-262 7.8.5
5953 if (isLineTerminator(ch.charCodeAt(0))) {
5954 throwUnexpectedToken(null, Messages.UnterminatedRegExp);
5955 }
5956 str += ch;
5957 } else if (isLineTerminator(ch.charCodeAt(0))) {
5958 throwUnexpectedToken(null, Messages.UnterminatedRegExp);
5959 } else if (classMarker) {
5960 if (ch === ']') {
5961 classMarker = false;
5962 }
5963 } else {
5964 if (ch === '/') {
5965 terminated = true;
5966 break;
5967 } else if (ch === '[') {
5968 classMarker = true;
5969 }
5970 }
5971 }
5972
5973 if (!terminated) {
5974 throwUnexpectedToken(null, Messages.UnterminatedRegExp);
5975 }
5976
5977 // Exclude leading and trailing slash.
5978 body = str.substr(1, str.length - 2);
5979 return {
5980 value: body,
5981 literal: str
5982 };
5983 }
5984
5985 function scanRegExpFlags() {
5986 var ch, str, flags, restore;
5987
5988 str = '';
5989 flags = '';
5990 while (index < length) {
5991 ch = source[index];
5992 if (!isIdentifierPart(ch.charCodeAt(0))) {
5993 break;
5994 }
5995
5996 ++index;
5997 if (ch === '\\' && index < length) {
5998 ch = source[index];
5999 if (ch === 'u') {
6000 ++index;
6001 restore = index;
6002 ch = scanHexEscape('u');
6003 if (ch) {
6004 flags += ch;
6005 for (str += '\\u'; restore < index; ++restore) {
6006 str += source[restore];
6007 }
6008 } else {
6009 index = restore;
6010 flags += 'u';
6011 str += '\\u';
6012 }
6013 tolerateUnexpectedToken();
6014 } else {
6015 str += '\\';
6016 tolerateUnexpectedToken();
6017 }
6018 } else {
6019 flags += ch;
6020 str += ch;
6021 }
6022 }
6023
6024 return {
6025 value: flags,
6026 literal: str
6027 };
6028 }
6029
6030 function scanRegExp() {
6031 var start, body, flags, value;
6032 scanning = true;
6033
6034 lookahead = null;
6035 skipComment();
6036 start = index;
6037
6038 body = scanRegExpBody();
6039 flags = scanRegExpFlags();
6040 value = testRegExp(body.value, flags.value);
6041 scanning = false;
6042 if (extra.tokenize) {
6043 return {
6044 type: Token.RegularExpression,
6045 value: value,
6046 regex: {
6047 pattern: body.value,
6048 flags: flags.value
6049 },
6050 lineNumber: lineNumber,
6051 lineStart: lineStart,
6052 start: start,
6053 end: index
6054 };
6055 }
6056
6057 return {
6058 literal: body.literal + flags.literal,
6059 value: value,
6060 regex: {
6061 pattern: body.value,
6062 flags: flags.value
6063 },
6064 start: start,
6065 end: index
6066 };
6067 }
6068
6069 function collectRegex() {
6070 var pos, loc, regex, token;
6071
6072 skipComment();
6073
6074 pos = index;
6075 loc = {
6076 start: {
6077 line: lineNumber,
6078 column: index - lineStart
6079 }
6080 };
6081
6082 regex = scanRegExp();
6083
6084 loc.end = {
6085 line: lineNumber,
6086 column: index - lineStart
6087 };
6088
6089 /* istanbul ignore next */
6090 if (!extra.tokenize) {
6091 // Pop the previous token, which is likely '/' or '/='
6092 if (extra.tokens.length > 0) {
6093 token = extra.tokens[extra.tokens.length - 1];
6094 if (token.range[0] === pos && token.type === 'Punctuator') {
6095 if (token.value === '/' || token.value === '/=') {
6096 extra.tokens.pop();
6097 }
6098 }
6099 }
6100
6101 extra.tokens.push({
6102 type: 'RegularExpression',
6103 value: regex.literal,
6104 regex: regex.regex,
6105 range: [pos, index],
6106 loc: loc
6107 });
6108 }
6109
6110 return regex;
6111 }
6112
6113 function isIdentifierName(token) {
6114 return token.type === Token.Identifier ||
6115 token.type === Token.Keyword ||
6116 token.type === Token.BooleanLiteral ||
6117 token.type === Token.NullLiteral;
6118 }
6119
6120 // Using the following algorithm:
6121 // https://github.com/mozilla/sweet.js/wiki/design
6122
6123 function advanceSlash() {
6124 var regex, previous, check;
6125
6126 function testKeyword(value) {
6127 return value && (value.length > 1) && (value[0] >= 'a') && (value[0] <= 'z');
6128 }
6129
6130 previous = extra.tokenValues[extra.tokens.length - 1];
6131 regex = (previous !== null);
6132
6133 switch (previous) {
6134 case 'this':
6135 case ']':
6136 regex = false;
6137 break;
6138
6139 case ')':
6140 check = extra.tokenValues[extra.openParenToken - 1];
6141 regex = (check === 'if' || check === 'while' || check === 'for' || check === 'with');
6142 break;
6143
6144 case '}':
6145 // Dividing a function by anything makes little sense,
6146 // but we have to check for that.
6147 regex = false;
6148 if (testKeyword(extra.tokenValues[extra.openCurlyToken - 3])) {
6149 // Anonymous function, e.g. function(){} /42
6150 check = extra.tokenValues[extra.openCurlyToken - 4];
6151 regex = check ? (FnExprTokens.indexOf(check) < 0) : false;
6152 } else if (testKeyword(extra.tokenValues[extra.openCurlyToken - 4])) {
6153 // Named function, e.g. function f(){} /42/
6154 check = extra.tokenValues[extra.openCurlyToken - 5];
6155 regex = check ? (FnExprTokens.indexOf(check) < 0) : true;
6156 }
6157 }
6158
6159 return regex ? collectRegex() : scanPunctuator();
6160 }
6161
6162 function advance() {
6163 var cp, token;
6164
6165 if (index >= length) {
6166 return {
6167 type: Token.EOF,
6168 lineNumber: lineNumber,
6169 lineStart: lineStart,
6170 start: index,
6171 end: index
6172 };
6173 }
6174
6175 cp = source.charCodeAt(index);
6176
6177 if (isIdentifierStart(cp)) {
6178 token = scanIdentifier();
6179 if (strict && isStrictModeReservedWord(token.value)) {
6180 token.type = Token.Keyword;
6181 }
6182 return token;
6183 }
6184
6185 // Very common: ( and ) and ;
6186 if (cp === 0x28 || cp === 0x29 || cp === 0x3B) {
6187 return scanPunctuator();
6188 }
6189
6190 // String literal starts with single quote (U+0027) or double quote (U+0022).
6191 if (cp === 0x27 || cp === 0x22) {
6192 return scanStringLiteral();
6193 }
6194
6195 // Dot (.) U+002E can also start a floating-point number, hence the need
6196 // to check the next character.
6197 if (cp === 0x2E) {
6198 if (isDecimalDigit(source.charCodeAt(index + 1))) {
6199 return scanNumericLiteral();
6200 }
6201 return scanPunctuator();
6202 }
6203
6204 if (isDecimalDigit(cp)) {
6205 return scanNumericLiteral();
6206 }
6207
6208 // Slash (/) U+002F can also start a regex.
6209 if (extra.tokenize && cp === 0x2F) {
6210 return advanceSlash();
6211 }
6212
6213 // Template literals start with ` (U+0060) for template head
6214 // or } (U+007D) for template middle or template tail.
6215 if (cp === 0x60 || (cp === 0x7D && state.curlyStack[state.curlyStack.length - 1] === '${')) {
6216 return scanTemplate();
6217 }
6218
6219 // Possible identifier start in a surrogate pair.
6220 if (cp >= 0xD800 && cp < 0xDFFF) {
6221 cp = codePointAt(index);
6222 if (isIdentifierStart(cp)) {
6223 return scanIdentifier();
6224 }
6225 }
6226
6227 return scanPunctuator();
6228 }
6229
6230 function collectToken() {
6231 var loc, token, value, entry;
6232
6233 loc = {
6234 start: {
6235 line: lineNumber,
6236 column: index - lineStart
6237 }
6238 };
6239
6240 token = advance();
6241 loc.end = {
6242 line: lineNumber,
6243 column: index - lineStart
6244 };
6245
6246 if (token.type !== Token.EOF) {
6247 value = source.slice(token.start, token.end);
6248 entry = {
6249 type: TokenName[token.type],
6250 value: value,
6251 range: [token.start, token.end],
6252 loc: loc
6253 };
6254 if (token.regex) {
6255 entry.regex = {
6256 pattern: token.regex.pattern,
6257 flags: token.regex.flags
6258 };
6259 }
6260 if (extra.tokenValues) {
6261 extra.tokenValues.push((entry.type === 'Punctuator' || entry.type === 'Keyword') ? entry.value : null);
6262 }
6263 if (extra.tokenize) {
6264 if (!extra.range) {
6265 delete entry.range;
6266 }
6267 if (!extra.loc) {
6268 delete entry.loc;
6269 }
6270 if (extra.delegate) {
6271 entry = extra.delegate(entry);
6272 }
6273 }
6274 extra.tokens.push(entry);
6275 }
6276
6277 return token;
6278 }
6279
6280 function lex() {
6281 var token;
6282 scanning = true;
6283
6284 lastIndex = index;
6285 lastLineNumber = lineNumber;
6286 lastLineStart = lineStart;
6287
6288 skipComment();
6289
6290 token = lookahead;
6291
6292 startIndex = index;
6293 startLineNumber = lineNumber;
6294 startLineStart = lineStart;
6295
6296 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
6297 scanning = false;
6298 return token;
6299 }
6300
6301 function peek() {
6302 scanning = true;
6303
6304 skipComment();
6305
6306 lastIndex = index;
6307 lastLineNumber = lineNumber;
6308 lastLineStart = lineStart;
6309
6310 startIndex = index;
6311 startLineNumber = lineNumber;
6312 startLineStart = lineStart;
6313
6314 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
6315 scanning = false;
6316 }
6317
6318 function Position() {
6319 this.line = startLineNumber;
6320 this.column = startIndex - startLineStart;
6321 }
6322
6323 function SourceLocation() {
6324 this.start = new Position();
6325 this.end = null;
6326 }
6327
6328 function WrappingSourceLocation(startToken) {
6329 this.start = {
6330 line: startToken.lineNumber,
6331 column: startToken.start - startToken.lineStart
6332 };
6333 this.end = null;
6334 }
6335
6336 function Node() {
6337 if (extra.range) {
6338 this.range = [startIndex, 0];
6339 }
6340 if (extra.loc) {
6341 this.loc = new SourceLocation();
6342 }
6343 }
6344
6345 function WrappingNode(startToken) {
6346 if (extra.range) {
6347 this.range = [startToken.start, 0];
6348 }
6349 if (extra.loc) {
6350 this.loc = new WrappingSourceLocation(startToken);
6351 }
6352 }
6353
6354 WrappingNode.prototype = Node.prototype = {
6355
6356 processComment: function () {
6357 var lastChild,
6358 innerComments,
6359 leadingComments,
6360 trailingComments,
6361 bottomRight = extra.bottomRightStack,
6362 i,
6363 comment,
6364 last = bottomRight[bottomRight.length - 1];
6365
6366 if (this.type === Syntax.Program) {
6367 if (this.body.length > 0) {
6368 return;
6369 }
6370 }
6371 /**
6372 * patch innnerComments for properties empty block
6373 * `function a() {/** comments **\/}`
6374 */
6375
6376 if (this.type === Syntax.BlockStatement && this.body.length === 0) {
6377 innerComments = [];
6378 for (i = extra.leadingComments.length - 1; i >= 0; --i) {
6379 comment = extra.leadingComments[i];
6380 if (this.range[1] >= comment.range[1]) {
6381 innerComments.unshift(comment);
6382 extra.leadingComments.splice(i, 1);
6383 extra.trailingComments.splice(i, 1);
6384 }
6385 }
6386 if (innerComments.length) {
6387 this.innerComments = innerComments;
6388 //bottomRight.push(this);
6389 return;
6390 }
6391 }
6392
6393 if (extra.trailingComments.length > 0) {
6394 trailingComments = [];
6395 for (i = extra.trailingComments.length - 1; i >= 0; --i) {
6396 comment = extra.trailingComments[i];
6397 if (comment.range[0] >= this.range[1]) {
6398 trailingComments.unshift(comment);
6399 extra.trailingComments.splice(i, 1);
6400 }
6401 }
6402 extra.trailingComments = [];
6403 } else {
6404 if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) {
6405 trailingComments = last.trailingComments;
6406 delete last.trailingComments;
6407 }
6408 }
6409
6410 // Eating the stack.
6411 while (last && last.range[0] >= this.range[0]) {
6412 lastChild = bottomRight.pop();
6413 last = bottomRight[bottomRight.length - 1];
6414 }
6415
6416 if (lastChild) {
6417 if (lastChild.leadingComments) {
6418 leadingComments = [];
6419 for (i = lastChild.leadingComments.length - 1; i >= 0; --i) {
6420 comment = lastChild.leadingComments[i];
6421 if (comment.range[1] <= this.range[0]) {
6422 leadingComments.unshift(comment);
6423 lastChild.leadingComments.splice(i, 1);
6424 }
6425 }
6426
6427 if (!lastChild.leadingComments.length) {
6428 lastChild.leadingComments = undefined;
6429 }
6430 }
6431 } else if (extra.leadingComments.length > 0) {
6432 leadingComments = [];
6433 for (i = extra.leadingComments.length - 1; i >= 0; --i) {
6434 comment = extra.leadingComments[i];
6435 if (comment.range[1] <= this.range[0]) {
6436 leadingComments.unshift(comment);
6437 extra.leadingComments.splice(i, 1);
6438 }
6439 }
6440 }
6441
6442
6443 if (leadingComments && leadingComments.length > 0) {
6444 this.leadingComments = leadingComments;
6445 }
6446 if (trailingComments && trailingComments.length > 0) {
6447 this.trailingComments = trailingComments;
6448 }
6449
6450 bottomRight.push(this);
6451 },
6452
6453 finish: function () {
6454 if (extra.range) {
6455 this.range[1] = lastIndex;
6456 }
6457 if (extra.loc) {
6458 this.loc.end = {
6459 line: lastLineNumber,
6460 column: lastIndex - lastLineStart
6461 };
6462 if (extra.source) {
6463 this.loc.source = extra.source;
6464 }
6465 }
6466
6467 if (extra.attachComment) {
6468 this.processComment();
6469 }
6470 },
6471
6472 finishArrayExpression: function (elements) {
6473 this.type = Syntax.ArrayExpression;
6474 this.elements = elements;
6475 this.finish();
6476 return this;
6477 },
6478
6479 finishArrayPattern: function (elements) {
6480 this.type = Syntax.ArrayPattern;
6481 this.elements = elements;
6482 this.finish();
6483 return this;
6484 },
6485
6486 finishArrowFunctionExpression: function (params, defaults, body, expression) {
6487 this.type = Syntax.ArrowFunctionExpression;
6488 this.id = null;
6489 this.params = params;
6490 this.defaults = defaults;
6491 this.body = body;
6492 this.generator = false;
6493 this.expression = expression;
6494 this.finish();
6495 return this;
6496 },
6497
6498 finishAssignmentExpression: function (operator, left, right) {
6499 this.type = Syntax.AssignmentExpression;
6500 this.operator = operator;
6501 this.left = left;
6502 this.right = right;
6503 this.finish();
6504 return this;
6505 },
6506
6507 finishAssignmentPattern: function (left, right) {
6508 this.type = Syntax.AssignmentPattern;
6509 this.left = left;
6510 this.right = right;
6511 this.finish();
6512 return this;
6513 },
6514
6515 finishBinaryExpression: function (operator, left, right) {
6516 this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression;
6517 this.operator = operator;
6518 this.left = left;
6519 this.right = right;
6520 this.finish();
6521 return this;
6522 },
6523
6524 finishBlockStatement: function (body) {
6525 this.type = Syntax.BlockStatement;
6526 this.body = body;
6527 this.finish();
6528 return this;
6529 },
6530
6531 finishBreakStatement: function (label) {
6532 this.type = Syntax.BreakStatement;
6533 this.label = label;
6534 this.finish();
6535 return this;
6536 },
6537
6538 finishCallExpression: function (callee, args) {
6539 this.type = Syntax.CallExpression;
6540 this.callee = callee;
6541 this.arguments = args;
6542 this.finish();
6543 return this;
6544 },
6545
6546 finishCatchClause: function (param, body) {
6547 this.type = Syntax.CatchClause;
6548 this.param = param;
6549 this.body = body;
6550 this.finish();
6551 return this;
6552 },
6553
6554 finishClassBody: function (body) {
6555 this.type = Syntax.ClassBody;
6556 this.body = body;
6557 this.finish();
6558 return this;
6559 },
6560
6561 finishClassDeclaration: function (id, superClass, body) {
6562 this.type = Syntax.ClassDeclaration;
6563 this.id = id;
6564 this.superClass = superClass;
6565 this.body = body;
6566 this.finish();
6567 return this;
6568 },
6569
6570 finishClassExpression: function (id, superClass, body) {
6571 this.type = Syntax.ClassExpression;
6572 this.id = id;
6573 this.superClass = superClass;
6574 this.body = body;
6575 this.finish();
6576 return this;
6577 },
6578
6579 finishConditionalExpression: function (test, consequent, alternate) {
6580 this.type = Syntax.ConditionalExpression;
6581 this.test = test;
6582 this.consequent = consequent;
6583 this.alternate = alternate;
6584 this.finish();
6585 return this;
6586 },
6587
6588 finishContinueStatement: function (label) {
6589 this.type = Syntax.ContinueStatement;
6590 this.label = label;
6591 this.finish();
6592 return this;
6593 },
6594
6595 finishDebuggerStatement: function () {
6596 this.type = Syntax.DebuggerStatement;
6597 this.finish();
6598 return this;
6599 },
6600
6601 finishDoWhileStatement: function (body, test) {
6602 this.type = Syntax.DoWhileStatement;
6603 this.body = body;
6604 this.test = test;
6605 this.finish();
6606 return this;
6607 },
6608
6609 finishEmptyStatement: function () {
6610 this.type = Syntax.EmptyStatement;
6611 this.finish();
6612 return this;
6613 },
6614
6615 finishExpressionStatement: function (expression) {
6616 this.type = Syntax.ExpressionStatement;
6617 this.expression = expression;
6618 this.finish();
6619 return this;
6620 },
6621
6622 finishForStatement: function (init, test, update, body) {
6623 this.type = Syntax.ForStatement;
6624 this.init = init;
6625 this.test = test;
6626 this.update = update;
6627 this.body = body;
6628 this.finish();
6629 return this;
6630 },
6631
6632 finishForOfStatement: function (left, right, body) {
6633 this.type = Syntax.ForOfStatement;
6634 this.left = left;
6635 this.right = right;
6636 this.body = body;
6637 this.finish();
6638 return this;
6639 },
6640
6641 finishForInStatement: function (left, right, body) {
6642 this.type = Syntax.ForInStatement;
6643 this.left = left;
6644 this.right = right;
6645 this.body = body;
6646 this.each = false;
6647 this.finish();
6648 return this;
6649 },
6650
6651 finishFunctionDeclaration: function (id, params, defaults, body, generator) {
6652 this.type = Syntax.FunctionDeclaration;
6653 this.id = id;
6654 this.params = params;
6655 this.defaults = defaults;
6656 this.body = body;
6657 this.generator = generator;
6658 this.expression = false;
6659 this.finish();
6660 return this;
6661 },
6662
6663 finishFunctionExpression: function (id, params, defaults, body, generator) {
6664 this.type = Syntax.FunctionExpression;
6665 this.id = id;
6666 this.params = params;
6667 this.defaults = defaults;
6668 this.body = body;
6669 this.generator = generator;
6670 this.expression = false;
6671 this.finish();
6672 return this;
6673 },
6674
6675 finishIdentifier: function (name) {
6676 this.type = Syntax.Identifier;
6677 this.name = name;
6678 this.finish();
6679 return this;
6680 },
6681
6682 finishIfStatement: function (test, consequent, alternate) {
6683 this.type = Syntax.IfStatement;
6684 this.test = test;
6685 this.consequent = consequent;
6686 this.alternate = alternate;
6687 this.finish();
6688 return this;
6689 },
6690
6691 finishLabeledStatement: function (label, body) {
6692 this.type = Syntax.LabeledStatement;
6693 this.label = label;
6694 this.body = body;
6695 this.finish();
6696 return this;
6697 },
6698
6699 finishLiteral: function (token) {
6700 this.type = Syntax.Literal;
6701 this.value = token.value;
6702 this.raw = source.slice(token.start, token.end);
6703 if (token.regex) {
6704 this.regex = token.regex;
6705 }
6706 this.finish();
6707 return this;
6708 },
6709
6710 finishMemberExpression: function (accessor, object, property) {
6711 this.type = Syntax.MemberExpression;
6712 this.computed = accessor === '[';
6713 this.object = object;
6714 this.property = property;
6715 this.finish();
6716 return this;
6717 },
6718
6719 finishMetaProperty: function (meta, property) {
6720 this.type = Syntax.MetaProperty;
6721 this.meta = meta;
6722 this.property = property;
6723 this.finish();
6724 return this;
6725 },
6726
6727 finishNewExpression: function (callee, args) {
6728 this.type = Syntax.NewExpression;
6729 this.callee = callee;
6730 this.arguments = args;
6731 this.finish();
6732 return this;
6733 },
6734
6735 finishObjectExpression: function (properties) {
6736 this.type = Syntax.ObjectExpression;
6737 this.properties = properties;
6738 this.finish();
6739 return this;
6740 },
6741
6742 finishObjectPattern: function (properties) {
6743 this.type = Syntax.ObjectPattern;
6744 this.properties = properties;
6745 this.finish();
6746 return this;
6747 },
6748
6749 finishPostfixExpression: function (operator, argument) {
6750 this.type = Syntax.UpdateExpression;
6751 this.operator = operator;
6752 this.argument = argument;
6753 this.prefix = false;
6754 this.finish();
6755 return this;
6756 },
6757
6758 finishProgram: function (body, sourceType) {
6759 this.type = Syntax.Program;
6760 this.body = body;
6761 this.sourceType = sourceType;
6762 this.finish();
6763 return this;
6764 },
6765
6766 finishProperty: function (kind, key, computed, value, method, shorthand) {
6767 this.type = Syntax.Property;
6768 this.key = key;
6769 this.computed = computed;
6770 this.value = value;
6771 this.kind = kind;
6772 this.method = method;
6773 this.shorthand = shorthand;
6774 this.finish();
6775 return this;
6776 },
6777
6778 finishRestElement: function (argument) {
6779 this.type = Syntax.RestElement;
6780 this.argument = argument;
6781 this.finish();
6782 return this;
6783 },
6784
6785 finishReturnStatement: function (argument) {
6786 this.type = Syntax.ReturnStatement;
6787 this.argument = argument;
6788 this.finish();
6789 return this;
6790 },
6791
6792 finishSequenceExpression: function (expressions) {
6793 this.type = Syntax.SequenceExpression;
6794 this.expressions = expressions;
6795 this.finish();
6796 return this;
6797 },
6798
6799 finishSpreadElement: function (argument) {
6800 this.type = Syntax.SpreadElement;
6801 this.argument = argument;
6802 this.finish();
6803 return this;
6804 },
6805
6806 finishSwitchCase: function (test, consequent) {
6807 this.type = Syntax.SwitchCase;
6808 this.test = test;
6809 this.consequent = consequent;
6810 this.finish();
6811 return this;
6812 },
6813
6814 finishSuper: function () {
6815 this.type = Syntax.Super;
6816 this.finish();
6817 return this;
6818 },
6819
6820 finishSwitchStatement: function (discriminant, cases) {
6821 this.type = Syntax.SwitchStatement;
6822 this.discriminant = discriminant;
6823 this.cases = cases;
6824 this.finish();
6825 return this;
6826 },
6827
6828 finishTaggedTemplateExpression: function (tag, quasi) {
6829 this.type = Syntax.TaggedTemplateExpression;
6830 this.tag = tag;
6831 this.quasi = quasi;
6832 this.finish();
6833 return this;
6834 },
6835
6836 finishTemplateElement: function (value, tail) {
6837 this.type = Syntax.TemplateElement;
6838 this.value = value;
6839 this.tail = tail;
6840 this.finish();
6841 return this;
6842 },
6843
6844 finishTemplateLiteral: function (quasis, expressions) {
6845 this.type = Syntax.TemplateLiteral;
6846 this.quasis = quasis;
6847 this.expressions = expressions;
6848 this.finish();
6849 return this;
6850 },
6851
6852 finishThisExpression: function () {
6853 this.type = Syntax.ThisExpression;
6854 this.finish();
6855 return this;
6856 },
6857
6858 finishThrowStatement: function (argument) {
6859 this.type = Syntax.ThrowStatement;
6860 this.argument = argument;
6861 this.finish();
6862 return this;
6863 },
6864
6865 finishTryStatement: function (block, handler, finalizer) {
6866 this.type = Syntax.TryStatement;
6867 this.block = block;
6868 this.guardedHandlers = [];
6869 this.handlers = handler ? [handler] : [];
6870 this.handler = handler;
6871 this.finalizer = finalizer;
6872 this.finish();
6873 return this;
6874 },
6875
6876 finishUnaryExpression: function (operator, argument) {
6877 this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression;
6878 this.operator = operator;
6879 this.argument = argument;
6880 this.prefix = true;
6881 this.finish();
6882 return this;
6883 },
6884
6885 finishVariableDeclaration: function (declarations) {
6886 this.type = Syntax.VariableDeclaration;
6887 this.declarations = declarations;
6888 this.kind = 'var';
6889 this.finish();
6890 return this;
6891 },
6892
6893 finishLexicalDeclaration: function (declarations, kind) {
6894 this.type = Syntax.VariableDeclaration;
6895 this.declarations = declarations;
6896 this.kind = kind;
6897 this.finish();
6898 return this;
6899 },
6900
6901 finishVariableDeclarator: function (id, init) {
6902 this.type = Syntax.VariableDeclarator;
6903 this.id = id;
6904 this.init = init;
6905 this.finish();
6906 return this;
6907 },
6908
6909 finishWhileStatement: function (test, body) {
6910 this.type = Syntax.WhileStatement;
6911 this.test = test;
6912 this.body = body;
6913 this.finish();
6914 return this;
6915 },
6916
6917 finishWithStatement: function (object, body) {
6918 this.type = Syntax.WithStatement;
6919 this.object = object;
6920 this.body = body;
6921 this.finish();
6922 return this;
6923 },
6924
6925 finishExportSpecifier: function (local, exported) {
6926 this.type = Syntax.ExportSpecifier;
6927 this.exported = exported || local;
6928 this.local = local;
6929 this.finish();
6930 return this;
6931 },
6932
6933 finishImportDefaultSpecifier: function (local) {
6934 this.type = Syntax.ImportDefaultSpecifier;
6935 this.local = local;
6936 this.finish();
6937 return this;
6938 },
6939
6940 finishImportNamespaceSpecifier: function (local) {
6941 this.type = Syntax.ImportNamespaceSpecifier;
6942 this.local = local;
6943 this.finish();
6944 return this;
6945 },
6946
6947 finishExportNamedDeclaration: function (declaration, specifiers, src) {
6948 this.type = Syntax.ExportNamedDeclaration;
6949 this.declaration = declaration;
6950 this.specifiers = specifiers;
6951 this.source = src;
6952 this.finish();
6953 return this;
6954 },
6955
6956 finishExportDefaultDeclaration: function (declaration) {
6957 this.type = Syntax.ExportDefaultDeclaration;
6958 this.declaration = declaration;
6959 this.finish();
6960 return this;
6961 },
6962
6963 finishExportAllDeclaration: function (src) {
6964 this.type = Syntax.ExportAllDeclaration;
6965 this.source = src;
6966 this.finish();
6967 return this;
6968 },
6969
6970 finishImportSpecifier: function (local, imported) {
6971 this.type = Syntax.ImportSpecifier;
6972 this.local = local || imported;
6973 this.imported = imported;
6974 this.finish();
6975 return this;
6976 },
6977
6978 finishImportDeclaration: function (specifiers, src) {
6979 this.type = Syntax.ImportDeclaration;
6980 this.specifiers = specifiers;
6981 this.source = src;
6982 this.finish();
6983 return this;
6984 },
6985
6986 finishYieldExpression: function (argument, delegate) {
6987 this.type = Syntax.YieldExpression;
6988 this.argument = argument;
6989 this.delegate = delegate;
6990 this.finish();
6991 return this;
6992 }
6993 };
6994
6995
6996 function recordError(error) {
6997 var e, existing;
6998
6999 for (e = 0; e < extra.errors.length; e++) {
7000 existing = extra.errors[e];
7001 // Prevent duplicated error.
7002 /* istanbul ignore next */
7003 if (existing.index === error.index && existing.message === error.message) {
7004 return;
7005 }
7006 }
7007
7008 extra.errors.push(error);
7009 }
7010
7011 function constructError(msg, column) {
7012 var error = new Error(msg);
7013 try {
7014 throw error;
7015 } catch (base) {
7016 /* istanbul ignore else */
7017 if (Object.create && Object.defineProperty) {
7018 error = Object.create(base);
7019 Object.defineProperty(error, 'column', { value: column });
7020 }
7021 } finally {
7022 return error;
7023 }
7024 }
7025
7026 function createError(line, pos, description) {
7027 var msg, column, error;
7028
7029 msg = 'Line ' + line + ': ' + description;
7030 column = pos - (scanning ? lineStart : lastLineStart) + 1;
7031 error = constructError(msg, column);
7032 error.lineNumber = line;
7033 error.description = description;
7034 error.index = pos;
7035 return error;
7036 }
7037
7038 // Throw an exception
7039
7040 function throwError(messageFormat) {
7041 var args, msg;
7042
7043 args = Array.prototype.slice.call(arguments, 1);
7044 msg = messageFormat.replace(/%(\d)/g,
7045 function (whole, idx) {
7046 assert(idx < args.length, 'Message reference must be in range');
7047 return args[idx];
7048 }
7049 );
7050
7051 throw createError(lastLineNumber, lastIndex, msg);
7052 }
7053
7054 function tolerateError(messageFormat) {
7055 var args, msg, error;
7056
7057 args = Array.prototype.slice.call(arguments, 1);
7058 /* istanbul ignore next */
7059 msg = messageFormat.replace(/%(\d)/g,
7060 function (whole, idx) {
7061 assert(idx < args.length, 'Message reference must be in range');
7062 return args[idx];
7063 }
7064 );
7065
7066 error = createError(lineNumber, lastIndex, msg);
7067 if (extra.errors) {
7068 recordError(error);
7069 } else {
7070 throw error;
7071 }
7072 }
7073
7074 // Throw an exception because of the token.
7075
7076 function unexpectedTokenError(token, message) {
7077 var value, msg = message || Messages.UnexpectedToken;
7078
7079 if (token) {
7080 if (!message) {
7081 msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS :
7082 (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier :
7083 (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber :
7084 (token.type === Token.StringLiteral) ? Messages.UnexpectedString :
7085 (token.type === Token.Template) ? Messages.UnexpectedTemplate :
7086 Messages.UnexpectedToken;
7087
7088 if (token.type === Token.Keyword) {
7089 if (isFutureReservedWord(token.value)) {
7090 msg = Messages.UnexpectedReserved;
7091 } else if (strict && isStrictModeReservedWord(token.value)) {
7092 msg = Messages.StrictReservedWord;
7093 }
7094 }
7095 }
7096
7097 value = (token.type === Token.Template) ? token.value.raw : token.value;
7098 } else {
7099 value = 'ILLEGAL';
7100 }
7101
7102 msg = msg.replace('%0', value);
7103
7104 return (token && typeof token.lineNumber === 'number') ?
7105 createError(token.lineNumber, token.start, msg) :
7106 createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg);
7107 }
7108
7109 function throwUnexpectedToken(token, message) {
7110 throw unexpectedTokenError(token, message);
7111 }
7112
7113 function tolerateUnexpectedToken(token, message) {
7114 var error = unexpectedTokenError(token, message);
7115 if (extra.errors) {
7116 recordError(error);
7117 } else {
7118 throw error;
7119 }
7120 }
7121
7122 // Expect the next token to match the specified punctuator.
7123 // If not, an exception will be thrown.
7124
7125 function expect(value) {
7126 var token = lex();
7127 if (token.type !== Token.Punctuator || token.value !== value) {
7128 throwUnexpectedToken(token);
7129 }
7130 }
7131
7132 /**
7133 * @name expectCommaSeparator
7134 * @description Quietly expect a comma when in tolerant mode, otherwise delegates
7135 * to <code>expect(value)</code>
7136 * @since 2.0
7137 */
7138 function expectCommaSeparator() {
7139 var token;
7140
7141 if (extra.errors) {
7142 token = lookahead;
7143 if (token.type === Token.Punctuator && token.value === ',') {
7144 lex();
7145 } else if (token.type === Token.Punctuator && token.value === ';') {
7146 lex();
7147 tolerateUnexpectedToken(token);
7148 } else {
7149 tolerateUnexpectedToken(token, Messages.UnexpectedToken);
7150 }
7151 } else {
7152 expect(',');
7153 }
7154 }
7155
7156 // Expect the next token to match the specified keyword.
7157 // If not, an exception will be thrown.
7158
7159 function expectKeyword(keyword) {
7160 var token = lex();
7161 if (token.type !== Token.Keyword || token.value !== keyword) {
7162 throwUnexpectedToken(token);
7163 }
7164 }
7165
7166 // Return true if the next token matches the specified punctuator.
7167
7168 function match(value) {
7169 return lookahead.type === Token.Punctuator && lookahead.value === value;
7170 }
7171
7172 // Return true if the next token matches the specified keyword
7173
7174 function matchKeyword(keyword) {
7175 return lookahead.type === Token.Keyword && lookahead.value === keyword;
7176 }
7177
7178 // Return true if the next token matches the specified contextual keyword
7179 // (where an identifier is sometimes a keyword depending on the context)
7180
7181 function matchContextualKeyword(keyword) {
7182 return lookahead.type === Token.Identifier && lookahead.value === keyword;
7183 }
7184
7185 // Return true if the next token is an assignment operator
7186
7187 function matchAssign() {
7188 var op;
7189
7190 if (lookahead.type !== Token.Punctuator) {
7191 return false;
7192 }
7193 op = lookahead.value;
7194 return op === '=' ||
7195 op === '*=' ||
7196 op === '/=' ||
7197 op === '%=' ||
7198 op === '+=' ||
7199 op === '-=' ||
7200 op === '<<=' ||
7201 op === '>>=' ||
7202 op === '>>>=' ||
7203 op === '&=' ||
7204 op === '^=' ||
7205 op === '|=';
7206 }
7207
7208 function consumeSemicolon() {
7209 // Catch the very common case first: immediately a semicolon (U+003B).
7210 if (source.charCodeAt(startIndex) === 0x3B || match(';')) {
7211 lex();
7212 return;
7213 }
7214
7215 if (hasLineTerminator) {
7216 return;
7217 }
7218
7219 // FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
7220 lastIndex = startIndex;
7221 lastLineNumber = startLineNumber;
7222 lastLineStart = startLineStart;
7223
7224 if (lookahead.type !== Token.EOF && !match('}')) {
7225 throwUnexpectedToken(lookahead);
7226 }
7227 }
7228
7229 // Cover grammar support.
7230 //
7231 // When an assignment expression position starts with an left parenthesis, the determination of the type
7232 // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
7233 // or the first comma. This situation also defers the determination of all the expressions nested in the pair.
7234 //
7235 // There are three productions that can be parsed in a parentheses pair that needs to be determined
7236 // after the outermost pair is closed. They are:
7237 //
7238 // 1. AssignmentExpression
7239 // 2. BindingElements
7240 // 3. AssignmentTargets
7241 //
7242 // In order to avoid exponential backtracking, we use two flags to denote if the production can be
7243 // binding element or assignment target.
7244 //
7245 // The three productions have the relationship:
7246 //
7247 // BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression
7248 //
7249 // with a single exception that CoverInitializedName when used directly in an Expression, generates
7250 // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
7251 // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
7252 //
7253 // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
7254 // effect the current flags. This means the production the parser parses is only used as an expression. Therefore
7255 // the CoverInitializedName check is conducted.
7256 //
7257 // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
7258 // the flags outside of the parser. This means the production the parser parses is used as a part of a potential
7259 // pattern. The CoverInitializedName check is deferred.
7260 function isolateCoverGrammar(parser) {
7261 var oldIsBindingElement = isBindingElement,
7262 oldIsAssignmentTarget = isAssignmentTarget,
7263 oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
7264 result;
7265 isBindingElement = true;
7266 isAssignmentTarget = true;
7267 firstCoverInitializedNameError = null;
7268 result = parser();
7269 if (firstCoverInitializedNameError !== null) {
7270 throwUnexpectedToken(firstCoverInitializedNameError);
7271 }
7272 isBindingElement = oldIsBindingElement;
7273 isAssignmentTarget = oldIsAssignmentTarget;
7274 firstCoverInitializedNameError = oldFirstCoverInitializedNameError;
7275 return result;
7276 }
7277
7278 function inheritCoverGrammar(parser) {
7279 var oldIsBindingElement = isBindingElement,
7280 oldIsAssignmentTarget = isAssignmentTarget,
7281 oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
7282 result;
7283 isBindingElement = true;
7284 isAssignmentTarget = true;
7285 firstCoverInitializedNameError = null;
7286 result = parser();
7287 isBindingElement = isBindingElement && oldIsBindingElement;
7288 isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget;
7289 firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError;
7290 return result;
7291 }
7292
7293 // ECMA-262 13.3.3 Destructuring Binding Patterns
7294
7295 function parseArrayPattern(params, kind) {
7296 var node = new Node(), elements = [], rest, restNode;
7297 expect('[');
7298
7299 while (!match(']')) {
7300 if (match(',')) {
7301 lex();
7302 elements.push(null);
7303 } else {
7304 if (match('...')) {
7305 restNode = new Node();
7306 lex();
7307 params.push(lookahead);
7308 rest = parseVariableIdentifier(kind);
7309 elements.push(restNode.finishRestElement(rest));
7310 break;
7311 } else {
7312 elements.push(parsePatternWithDefault(params, kind));
7313 }
7314 if (!match(']')) {
7315 expect(',');
7316 }
7317 }
7318
7319 }
7320
7321 expect(']');
7322
7323 return node.finishArrayPattern(elements);
7324 }
7325
7326 function parsePropertyPattern(params, kind) {
7327 var node = new Node(), key, keyToken, computed = match('['), init;
7328 if (lookahead.type === Token.Identifier) {
7329 keyToken = lookahead;
7330 key = parseVariableIdentifier();
7331 if (match('=')) {
7332 params.push(keyToken);
7333 lex();
7334 init = parseAssignmentExpression();
7335
7336 return node.finishProperty(
7337 'init', key, false,
7338 new WrappingNode(keyToken).finishAssignmentPattern(key, init), false, false);
7339 } else if (!match(':')) {
7340 params.push(keyToken);
7341 return node.finishProperty('init', key, false, key, false, true);
7342 }
7343 } else {
7344 key = parseObjectPropertyKey();
7345 }
7346 expect(':');
7347 init = parsePatternWithDefault(params, kind);
7348 return node.finishProperty('init', key, computed, init, false, false);
7349 }
7350
7351 function parseObjectPattern(params, kind) {
7352 var node = new Node(), properties = [];
7353
7354 expect('{');
7355
7356 while (!match('}')) {
7357 properties.push(parsePropertyPattern(params, kind));
7358 if (!match('}')) {
7359 expect(',');
7360 }
7361 }
7362
7363 lex();
7364
7365 return node.finishObjectPattern(properties);
7366 }
7367
7368 function parsePattern(params, kind) {
7369 if (match('[')) {
7370 return parseArrayPattern(params, kind);
7371 } else if (match('{')) {
7372 return parseObjectPattern(params, kind);
7373 } else if (matchKeyword('let')) {
7374 if (kind === 'const' || kind === 'let') {
7375 tolerateUnexpectedToken(lookahead, Messages.UnexpectedToken);
7376 }
7377 }
7378
7379 params.push(lookahead);
7380 return parseVariableIdentifier(kind);
7381 }
7382
7383 function parsePatternWithDefault(params, kind) {
7384 var startToken = lookahead, pattern, previousAllowYield, right;
7385 pattern = parsePattern(params, kind);
7386 if (match('=')) {
7387 lex();
7388 previousAllowYield = state.allowYield;
7389 state.allowYield = true;
7390 right = isolateCoverGrammar(parseAssignmentExpression);
7391 state.allowYield = previousAllowYield;
7392 pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right);
7393 }
7394 return pattern;
7395 }
7396
7397 // ECMA-262 12.2.5 Array Initializer
7398
7399 function parseArrayInitializer() {
7400 var elements = [], node = new Node(), restSpread;
7401
7402 expect('[');
7403
7404 while (!match(']')) {
7405 if (match(',')) {
7406 lex();
7407 elements.push(null);
7408 } else if (match('...')) {
7409 restSpread = new Node();
7410 lex();
7411 restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression));
7412
7413 if (!match(']')) {
7414 isAssignmentTarget = isBindingElement = false;
7415 expect(',');
7416 }
7417 elements.push(restSpread);
7418 } else {
7419 elements.push(inheritCoverGrammar(parseAssignmentExpression));
7420
7421 if (!match(']')) {
7422 expect(',');
7423 }
7424 }
7425 }
7426
7427 lex();
7428
7429 return node.finishArrayExpression(elements);
7430 }
7431
7432 // ECMA-262 12.2.6 Object Initializer
7433
7434 function parsePropertyFunction(node, paramInfo, isGenerator) {
7435 var previousStrict, body;
7436
7437 isAssignmentTarget = isBindingElement = false;
7438
7439 previousStrict = strict;
7440 body = isolateCoverGrammar(parseFunctionSourceElements);
7441
7442 if (strict && paramInfo.firstRestricted) {
7443 tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message);
7444 }
7445 if (strict && paramInfo.stricted) {
7446 tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message);
7447 }
7448
7449 strict = previousStrict;
7450 return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body, isGenerator);
7451 }
7452
7453 function parsePropertyMethodFunction() {
7454 var params, method, node = new Node(),
7455 previousAllowYield = state.allowYield;
7456
7457 state.allowYield = false;
7458 params = parseParams();
7459 state.allowYield = previousAllowYield;
7460
7461 state.allowYield = false;
7462 method = parsePropertyFunction(node, params, false);
7463 state.allowYield = previousAllowYield;
7464
7465 return method;
7466 }
7467
7468 function parseObjectPropertyKey() {
7469 var token, node = new Node(), expr;
7470
7471 token = lex();
7472
7473 // Note: This function is called only from parseObjectProperty(), where
7474 // EOF and Punctuator tokens are already filtered out.
7475
7476 switch (token.type) {
7477 case Token.StringLiteral:
7478 case Token.NumericLiteral:
7479 if (strict && token.octal) {
7480 tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
7481 }
7482 return node.finishLiteral(token);
7483 case Token.Identifier:
7484 case Token.BooleanLiteral:
7485 case Token.NullLiteral:
7486 case Token.Keyword:
7487 return node.finishIdentifier(token.value);
7488 case Token.Punctuator:
7489 if (token.value === '[') {
7490 expr = isolateCoverGrammar(parseAssignmentExpression);
7491 expect(']');
7492 return expr;
7493 }
7494 break;
7495 }
7496 throwUnexpectedToken(token);
7497 }
7498
7499 function lookaheadPropertyName() {
7500 switch (lookahead.type) {
7501 case Token.Identifier:
7502 case Token.StringLiteral:
7503 case Token.BooleanLiteral:
7504 case Token.NullLiteral:
7505 case Token.NumericLiteral:
7506 case Token.Keyword:
7507 return true;
7508 case Token.Punctuator:
7509 return lookahead.value === '[';
7510 }
7511 return false;
7512 }
7513
7514 // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
7515 // it might be called at a position where there is in fact a short hand identifier pattern or a data property.
7516 // This can only be determined after we consumed up to the left parentheses.
7517 //
7518 // In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
7519 // is responsible to visit other options.
7520 function tryParseMethodDefinition(token, key, computed, node) {
7521 var value, options, methodNode, params,
7522 previousAllowYield = state.allowYield;
7523
7524 if (token.type === Token.Identifier) {
7525 // check for `get` and `set`;
7526
7527 if (token.value === 'get' && lookaheadPropertyName()) {
7528 computed = match('[');
7529 key = parseObjectPropertyKey();
7530 methodNode = new Node();
7531 expect('(');
7532 expect(')');
7533
7534 state.allowYield = false;
7535 value = parsePropertyFunction(methodNode, {
7536 params: [],
7537 defaults: [],
7538 stricted: null,
7539 firstRestricted: null,
7540 message: null
7541 }, false);
7542 state.allowYield = previousAllowYield;
7543
7544 return node.finishProperty('get', key, computed, value, false, false);
7545 } else if (token.value === 'set' && lookaheadPropertyName()) {
7546 computed = match('[');
7547 key = parseObjectPropertyKey();
7548 methodNode = new Node();
7549 expect('(');
7550
7551 options = {
7552 params: [],
7553 defaultCount: 0,
7554 defaults: [],
7555 firstRestricted: null,
7556 paramSet: {}
7557 };
7558 if (match(')')) {
7559 tolerateUnexpectedToken(lookahead);
7560 } else {
7561 state.allowYield = false;
7562 parseParam(options);
7563 state.allowYield = previousAllowYield;
7564 if (options.defaultCount === 0) {
7565 options.defaults = [];
7566 }
7567 }
7568 expect(')');
7569
7570 state.allowYield = false;
7571 value = parsePropertyFunction(methodNode, options, false);
7572 state.allowYield = previousAllowYield;
7573
7574 return node.finishProperty('set', key, computed, value, false, false);
7575 }
7576 } else if (token.type === Token.Punctuator && token.value === '*' && lookaheadPropertyName()) {
7577 computed = match('[');
7578 key = parseObjectPropertyKey();
7579 methodNode = new Node();
7580
7581 state.allowYield = true;
7582 params = parseParams();
7583 state.allowYield = previousAllowYield;
7584
7585 state.allowYield = false;
7586 value = parsePropertyFunction(methodNode, params, true);
7587 state.allowYield = previousAllowYield;
7588
7589 return node.finishProperty('init', key, computed, value, true, false);
7590 }
7591
7592 if (key && match('(')) {
7593 value = parsePropertyMethodFunction();
7594 return node.finishProperty('init', key, computed, value, true, false);
7595 }
7596
7597 // Not a MethodDefinition.
7598 return null;
7599 }
7600
7601 function parseObjectProperty(hasProto) {
7602 var token = lookahead, node = new Node(), computed, key, maybeMethod, proto, value;
7603
7604 computed = match('[');
7605 if (match('*')) {
7606 lex();
7607 } else {
7608 key = parseObjectPropertyKey();
7609 }
7610 maybeMethod = tryParseMethodDefinition(token, key, computed, node);
7611 if (maybeMethod) {
7612 return maybeMethod;
7613 }
7614
7615 if (!key) {
7616 throwUnexpectedToken(lookahead);
7617 }
7618
7619 // Check for duplicated __proto__
7620 if (!computed) {
7621 proto = (key.type === Syntax.Identifier && key.name === '__proto__') ||
7622 (key.type === Syntax.Literal && key.value === '__proto__');
7623 if (hasProto.value && proto) {
7624 tolerateError(Messages.DuplicateProtoProperty);
7625 }
7626 hasProto.value |= proto;
7627 }
7628
7629 if (match(':')) {
7630 lex();
7631 value = inheritCoverGrammar(parseAssignmentExpression);
7632 return node.finishProperty('init', key, computed, value, false, false);
7633 }
7634
7635 if (token.type === Token.Identifier) {
7636 if (match('=')) {
7637 firstCoverInitializedNameError = lookahead;
7638 lex();
7639 value = isolateCoverGrammar(parseAssignmentExpression);
7640 return node.finishProperty('init', key, computed,
7641 new WrappingNode(token).finishAssignmentPattern(key, value), false, true);
7642 }
7643 return node.finishProperty('init', key, computed, key, false, true);
7644 }
7645
7646 throwUnexpectedToken(lookahead);
7647 }
7648
7649 function parseObjectInitializer() {
7650 var properties = [], hasProto = {value: false}, node = new Node();
7651
7652 expect('{');
7653
7654 while (!match('}')) {
7655 properties.push(parseObjectProperty(hasProto));
7656
7657 if (!match('}')) {
7658 expectCommaSeparator();
7659 }
7660 }
7661
7662 expect('}');
7663
7664 return node.finishObjectExpression(properties);
7665 }
7666
7667 function reinterpretExpressionAsPattern(expr) {
7668 var i;
7669 switch (expr.type) {
7670 case Syntax.Identifier:
7671 case Syntax.MemberExpression:
7672 case Syntax.RestElement:
7673 case Syntax.AssignmentPattern:
7674 break;
7675 case Syntax.SpreadElement:
7676 expr.type = Syntax.RestElement;
7677 reinterpretExpressionAsPattern(expr.argument);
7678 break;
7679 case Syntax.ArrayExpression:
7680 expr.type = Syntax.ArrayPattern;
7681 for (i = 0; i < expr.elements.length; i++) {
7682 if (expr.elements[i] !== null) {
7683 reinterpretExpressionAsPattern(expr.elements[i]);
7684 }
7685 }
7686 break;
7687 case Syntax.ObjectExpression:
7688 expr.type = Syntax.ObjectPattern;
7689 for (i = 0; i < expr.properties.length; i++) {
7690 reinterpretExpressionAsPattern(expr.properties[i].value);
7691 }
7692 break;
7693 case Syntax.AssignmentExpression:
7694 expr.type = Syntax.AssignmentPattern;
7695 reinterpretExpressionAsPattern(expr.left);
7696 break;
7697 default:
7698 // Allow other node type for tolerant parsing.
7699 break;
7700 }
7701 }
7702
7703 // ECMA-262 12.2.9 Template Literals
7704
7705 function parseTemplateElement(option) {
7706 var node, token;
7707
7708 if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) {
7709 throwUnexpectedToken();
7710 }
7711
7712 node = new Node();
7713 token = lex();
7714
7715 return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail);
7716 }
7717
7718 function parseTemplateLiteral() {
7719 var quasi, quasis, expressions, node = new Node();
7720
7721 quasi = parseTemplateElement({ head: true });
7722 quasis = [quasi];
7723 expressions = [];
7724
7725 while (!quasi.tail) {
7726 expressions.push(parseExpression());
7727 quasi = parseTemplateElement({ head: false });
7728 quasis.push(quasi);
7729 }
7730
7731 return node.finishTemplateLiteral(quasis, expressions);
7732 }
7733
7734 // ECMA-262 12.2.10 The Grouping Operator
7735
7736 function parseGroupExpression() {
7737 var expr, expressions, startToken, i, params = [];
7738
7739 expect('(');
7740
7741 if (match(')')) {
7742 lex();
7743 if (!match('=>')) {
7744 expect('=>');
7745 }
7746 return {
7747 type: PlaceHolders.ArrowParameterPlaceHolder,
7748 params: [],
7749 rawParams: []
7750 };
7751 }
7752
7753 startToken = lookahead;
7754 if (match('...')) {
7755 expr = parseRestElement(params);
7756 expect(')');
7757 if (!match('=>')) {
7758 expect('=>');
7759 }
7760 return {
7761 type: PlaceHolders.ArrowParameterPlaceHolder,
7762 params: [expr]
7763 };
7764 }
7765
7766 isBindingElement = true;
7767 expr = inheritCoverGrammar(parseAssignmentExpression);
7768
7769 if (match(',')) {
7770 isAssignmentTarget = false;
7771 expressions = [expr];
7772
7773 while (startIndex < length) {
7774 if (!match(',')) {
7775 break;
7776 }
7777 lex();
7778
7779 if (match('...')) {
7780 if (!isBindingElement) {
7781 throwUnexpectedToken(lookahead);
7782 }
7783 expressions.push(parseRestElement(params));
7784 expect(')');
7785 if (!match('=>')) {
7786 expect('=>');
7787 }
7788 isBindingElement = false;
7789 for (i = 0; i < expressions.length; i++) {
7790 reinterpretExpressionAsPattern(expressions[i]);
7791 }
7792 return {
7793 type: PlaceHolders.ArrowParameterPlaceHolder,
7794 params: expressions
7795 };
7796 }
7797
7798 expressions.push(inheritCoverGrammar(parseAssignmentExpression));
7799 }
7800
7801 expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
7802 }
7803
7804
7805 expect(')');
7806
7807 if (match('=>')) {
7808 if (expr.type === Syntax.Identifier && expr.name === 'yield') {
7809 return {
7810 type: PlaceHolders.ArrowParameterPlaceHolder,
7811 params: [expr]
7812 };
7813 }
7814
7815 if (!isBindingElement) {
7816 throwUnexpectedToken(lookahead);
7817 }
7818
7819 if (expr.type === Syntax.SequenceExpression) {
7820 for (i = 0; i < expr.expressions.length; i++) {
7821 reinterpretExpressionAsPattern(expr.expressions[i]);
7822 }
7823 } else {
7824 reinterpretExpressionAsPattern(expr);
7825 }
7826
7827 expr = {
7828 type: PlaceHolders.ArrowParameterPlaceHolder,
7829 params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr]
7830 };
7831 }
7832 isBindingElement = false;
7833 return expr;
7834 }
7835
7836
7837 // ECMA-262 12.2 Primary Expressions
7838
7839 function parsePrimaryExpression() {
7840 var type, token, expr, node;
7841
7842 if (match('(')) {
7843 isBindingElement = false;
7844 return inheritCoverGrammar(parseGroupExpression);
7845 }
7846
7847 if (match('[')) {
7848 return inheritCoverGrammar(parseArrayInitializer);
7849 }
7850
7851 if (match('{')) {
7852 return inheritCoverGrammar(parseObjectInitializer);
7853 }
7854
7855 type = lookahead.type;
7856 node = new Node();
7857
7858 if (type === Token.Identifier) {
7859 if (state.sourceType === 'module' && lookahead.value === 'await') {
7860 tolerateUnexpectedToken(lookahead);
7861 }
7862 expr = node.finishIdentifier(lex().value);
7863 } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
7864 isAssignmentTarget = isBindingElement = false;
7865 if (strict && lookahead.octal) {
7866 tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral);
7867 }
7868 expr = node.finishLiteral(lex());
7869 } else if (type === Token.Keyword) {
7870 if (!strict && state.allowYield && matchKeyword('yield')) {
7871 return parseNonComputedProperty();
7872 }
7873 isAssignmentTarget = isBindingElement = false;
7874 if (matchKeyword('function')) {
7875 return parseFunctionExpression();
7876 }
7877 if (matchKeyword('this')) {
7878 lex();
7879 return node.finishThisExpression();
7880 }
7881 if (matchKeyword('class')) {
7882 return parseClassExpression();
7883 }
7884 if (!strict && matchKeyword('let')) {
7885 return node.finishIdentifier(lex().value);
7886 }
7887 throwUnexpectedToken(lex());
7888 } else if (type === Token.BooleanLiteral) {
7889 isAssignmentTarget = isBindingElement = false;
7890 token = lex();
7891 token.value = (token.value === 'true');
7892 expr = node.finishLiteral(token);
7893 } else if (type === Token.NullLiteral) {
7894 isAssignmentTarget = isBindingElement = false;
7895 token = lex();
7896 token.value = null;
7897 expr = node.finishLiteral(token);
7898 } else if (match('/') || match('/=')) {
7899 isAssignmentTarget = isBindingElement = false;
7900 index = startIndex;
7901
7902 if (typeof extra.tokens !== 'undefined') {
7903 token = collectRegex();
7904 } else {
7905 token = scanRegExp();
7906 }
7907 lex();
7908 expr = node.finishLiteral(token);
7909 } else if (type === Token.Template) {
7910 expr = parseTemplateLiteral();
7911 } else {
7912 throwUnexpectedToken(lex());
7913 }
7914
7915 return expr;
7916 }
7917
7918 // ECMA-262 12.3 Left-Hand-Side Expressions
7919
7920 function parseArguments() {
7921 var args = [], expr;
7922
7923 expect('(');
7924
7925 if (!match(')')) {
7926 while (startIndex < length) {
7927 if (match('...')) {
7928 expr = new Node();
7929 lex();
7930 expr.finishSpreadElement(isolateCoverGrammar(parseAssignmentExpression));
7931 } else {
7932 expr = isolateCoverGrammar(parseAssignmentExpression);
7933 }
7934 args.push(expr);
7935 if (match(')')) {
7936 break;
7937 }
7938 expectCommaSeparator();
7939 }
7940 }
7941
7942 expect(')');
7943
7944 return args;
7945 }
7946
7947 function parseNonComputedProperty() {
7948 var token, node = new Node();
7949
7950 token = lex();
7951
7952 if (!isIdentifierName(token)) {
7953 throwUnexpectedToken(token);
7954 }
7955
7956 return node.finishIdentifier(token.value);
7957 }
7958
7959 function parseNonComputedMember() {
7960 expect('.');
7961
7962 return parseNonComputedProperty();
7963 }
7964
7965 function parseComputedMember() {
7966 var expr;
7967
7968 expect('[');
7969
7970 expr = isolateCoverGrammar(parseExpression);
7971
7972 expect(']');
7973
7974 return expr;
7975 }
7976
7977 // ECMA-262 12.3.3 The new Operator
7978
7979 function parseNewExpression() {
7980 var callee, args, node = new Node();
7981
7982 expectKeyword('new');
7983
7984 if (match('.')) {
7985 lex();
7986 if (lookahead.type === Token.Identifier && lookahead.value === 'target') {
7987 if (state.inFunctionBody) {
7988 lex();
7989 return node.finishMetaProperty('new', 'target');
7990 }
7991 }
7992 throwUnexpectedToken(lookahead);
7993 }
7994
7995 callee = isolateCoverGrammar(parseLeftHandSideExpression);
7996 args = match('(') ? parseArguments() : [];
7997
7998 isAssignmentTarget = isBindingElement = false;
7999
8000 return node.finishNewExpression(callee, args);
8001 }
8002
8003 // ECMA-262 12.3.4 Function Calls
8004
8005 function parseLeftHandSideExpressionAllowCall() {
8006 var quasi, expr, args, property, startToken, previousAllowIn = state.allowIn;
8007
8008 startToken = lookahead;
8009 state.allowIn = true;
8010
8011 if (matchKeyword('super') && state.inFunctionBody) {
8012 expr = new Node();
8013 lex();
8014 expr = expr.finishSuper();
8015 if (!match('(') && !match('.') && !match('[')) {
8016 throwUnexpectedToken(lookahead);
8017 }
8018 } else {
8019 expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
8020 }
8021
8022 for (;;) {
8023 if (match('.')) {
8024 isBindingElement = false;
8025 isAssignmentTarget = true;
8026 property = parseNonComputedMember();
8027 expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
8028 } else if (match('(')) {
8029 isBindingElement = false;
8030 isAssignmentTarget = false;
8031 args = parseArguments();
8032 expr = new WrappingNode(startToken).finishCallExpression(expr, args);
8033 } else if (match('[')) {
8034 isBindingElement = false;
8035 isAssignmentTarget = true;
8036 property = parseComputedMember();
8037 expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
8038 } else if (lookahead.type === Token.Template && lookahead.head) {
8039 quasi = parseTemplateLiteral();
8040 expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
8041 } else {
8042 break;
8043 }
8044 }
8045 state.allowIn = previousAllowIn;
8046
8047 return expr;
8048 }
8049
8050 // ECMA-262 12.3 Left-Hand-Side Expressions
8051
8052 function parseLeftHandSideExpression() {
8053 var quasi, expr, property, startToken;
8054 assert(state.allowIn, 'callee of new expression always allow in keyword.');
8055
8056 startToken = lookahead;
8057
8058 if (matchKeyword('super') && state.inFunctionBody) {
8059 expr = new Node();
8060 lex();
8061 expr = expr.finishSuper();
8062 if (!match('[') && !match('.')) {
8063 throwUnexpectedToken(lookahead);
8064 }
8065 } else {
8066 expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
8067 }
8068
8069 for (;;) {
8070 if (match('[')) {
8071 isBindingElement = false;
8072 isAssignmentTarget = true;
8073 property = parseComputedMember();
8074 expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
8075 } else if (match('.')) {
8076 isBindingElement = false;
8077 isAssignmentTarget = true;
8078 property = parseNonComputedMember();
8079 expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
8080 } else if (lookahead.type === Token.Template && lookahead.head) {
8081 quasi = parseTemplateLiteral();
8082 expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
8083 } else {
8084 break;
8085 }
8086 }
8087 return expr;
8088 }
8089
8090 // ECMA-262 12.4 Postfix Expressions
8091
8092 function parsePostfixExpression() {
8093 var expr, token, startToken = lookahead;
8094
8095 expr = inheritCoverGrammar(parseLeftHandSideExpressionAllowCall);
8096
8097 if (!hasLineTerminator && lookahead.type === Token.Punctuator) {
8098 if (match('++') || match('--')) {
8099 // ECMA-262 11.3.1, 11.3.2
8100 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
8101 tolerateError(Messages.StrictLHSPostfix);
8102 }
8103
8104 if (!isAssignmentTarget) {
8105 tolerateError(Messages.InvalidLHSInAssignment);
8106 }
8107
8108 isAssignmentTarget = isBindingElement = false;
8109
8110 token = lex();
8111 expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr);
8112 }
8113 }
8114
8115 return expr;
8116 }
8117
8118 // ECMA-262 12.5 Unary Operators
8119
8120 function parseUnaryExpression() {
8121 var token, expr, startToken;
8122
8123 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
8124 expr = parsePostfixExpression();
8125 } else if (match('++') || match('--')) {
8126 startToken = lookahead;
8127 token = lex();
8128 expr = inheritCoverGrammar(parseUnaryExpression);
8129 // ECMA-262 11.4.4, 11.4.5
8130 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
8131 tolerateError(Messages.StrictLHSPrefix);
8132 }
8133
8134 if (!isAssignmentTarget) {
8135 tolerateError(Messages.InvalidLHSInAssignment);
8136 }
8137 expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
8138 isAssignmentTarget = isBindingElement = false;
8139 } else if (match('+') || match('-') || match('~') || match('!')) {
8140 startToken = lookahead;
8141 token = lex();
8142 expr = inheritCoverGrammar(parseUnaryExpression);
8143 expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
8144 isAssignmentTarget = isBindingElement = false;
8145 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
8146 startToken = lookahead;
8147 token = lex();
8148 expr = inheritCoverGrammar(parseUnaryExpression);
8149 expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
8150 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
8151 tolerateError(Messages.StrictDelete);
8152 }
8153 isAssignmentTarget = isBindingElement = false;
8154 } else {
8155 expr = parsePostfixExpression();
8156 }
8157
8158 return expr;
8159 }
8160
8161 function binaryPrecedence(token, allowIn) {
8162 var prec = 0;
8163
8164 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
8165 return 0;
8166 }
8167
8168 switch (token.value) {
8169 case '||':
8170 prec = 1;
8171 break;
8172
8173 case '&&':
8174 prec = 2;
8175 break;
8176
8177 case '|':
8178 prec = 3;
8179 break;
8180
8181 case '^':
8182 prec = 4;
8183 break;
8184
8185 case '&':
8186 prec = 5;
8187 break;
8188
8189 case '==':
8190 case '!=':
8191 case '===':
8192 case '!==':
8193 prec = 6;
8194 break;
8195
8196 case '<':
8197 case '>':
8198 case '<=':
8199 case '>=':
8200 case 'instanceof':
8201 prec = 7;
8202 break;
8203
8204 case 'in':
8205 prec = allowIn ? 7 : 0;
8206 break;
8207
8208 case '<<':
8209 case '>>':
8210 case '>>>':
8211 prec = 8;
8212 break;
8213
8214 case '+':
8215 case '-':
8216 prec = 9;
8217 break;
8218
8219 case '*':
8220 case '/':
8221 case '%':
8222 prec = 11;
8223 break;
8224
8225 default:
8226 break;
8227 }
8228
8229 return prec;
8230 }
8231
8232 // ECMA-262 12.6 Multiplicative Operators
8233 // ECMA-262 12.7 Additive Operators
8234 // ECMA-262 12.8 Bitwise Shift Operators
8235 // ECMA-262 12.9 Relational Operators
8236 // ECMA-262 12.10 Equality Operators
8237 // ECMA-262 12.11 Binary Bitwise Operators
8238 // ECMA-262 12.12 Binary Logical Operators
8239
8240 function parseBinaryExpression() {
8241 var marker, markers, expr, token, prec, stack, right, operator, left, i;
8242
8243 marker = lookahead;
8244 left = inheritCoverGrammar(parseUnaryExpression);
8245
8246 token = lookahead;
8247 prec = binaryPrecedence(token, state.allowIn);
8248 if (prec === 0) {
8249 return left;
8250 }
8251 isAssignmentTarget = isBindingElement = false;
8252 token.prec = prec;
8253 lex();
8254
8255 markers = [marker, lookahead];
8256 right = isolateCoverGrammar(parseUnaryExpression);
8257
8258 stack = [left, token, right];
8259
8260 while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
8261
8262 // Reduce: make a binary expression from the three topmost entries.
8263 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
8264 right = stack.pop();
8265 operator = stack.pop().value;
8266 left = stack.pop();
8267 markers.pop();
8268 expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right);
8269 stack.push(expr);
8270 }
8271
8272 // Shift.
8273 token = lex();
8274 token.prec = prec;
8275 stack.push(token);
8276 markers.push(lookahead);
8277 expr = isolateCoverGrammar(parseUnaryExpression);
8278 stack.push(expr);
8279 }
8280
8281 // Final reduce to clean-up the stack.
8282 i = stack.length - 1;
8283 expr = stack[i];
8284 markers.pop();
8285 while (i > 1) {
8286 expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
8287 i -= 2;
8288 }
8289
8290 return expr;
8291 }
8292
8293
8294 // ECMA-262 12.13 Conditional Operator
8295
8296 function parseConditionalExpression() {
8297 var expr, previousAllowIn, consequent, alternate, startToken;
8298
8299 startToken = lookahead;
8300
8301 expr = inheritCoverGrammar(parseBinaryExpression);
8302 if (match('?')) {
8303 lex();
8304 previousAllowIn = state.allowIn;
8305 state.allowIn = true;
8306 consequent = isolateCoverGrammar(parseAssignmentExpression);
8307 state.allowIn = previousAllowIn;
8308 expect(':');
8309 alternate = isolateCoverGrammar(parseAssignmentExpression);
8310
8311 expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
8312 isAssignmentTarget = isBindingElement = false;
8313 }
8314
8315 return expr;
8316 }
8317
8318 // ECMA-262 14.2 Arrow Function Definitions
8319
8320 function parseConciseBody() {
8321 if (match('{')) {
8322 return parseFunctionSourceElements();
8323 }
8324 return isolateCoverGrammar(parseAssignmentExpression);
8325 }
8326
8327 function checkPatternParam(options, param) {
8328 var i;
8329 switch (param.type) {
8330 case Syntax.Identifier:
8331 validateParam(options, param, param.name);
8332 break;
8333 case Syntax.RestElement:
8334 checkPatternParam(options, param.argument);
8335 break;
8336 case Syntax.AssignmentPattern:
8337 checkPatternParam(options, param.left);
8338 break;
8339 case Syntax.ArrayPattern:
8340 for (i = 0; i < param.elements.length; i++) {
8341 if (param.elements[i] !== null) {
8342 checkPatternParam(options, param.elements[i]);
8343 }
8344 }
8345 break;
8346 case Syntax.YieldExpression:
8347 break;
8348 default:
8349 assert(param.type === Syntax.ObjectPattern, 'Invalid type');
8350 for (i = 0; i < param.properties.length; i++) {
8351 checkPatternParam(options, param.properties[i].value);
8352 }
8353 break;
8354 }
8355 }
8356 function reinterpretAsCoverFormalsList(expr) {
8357 var i, len, param, params, defaults, defaultCount, options, token;
8358
8359 defaults = [];
8360 defaultCount = 0;
8361 params = [expr];
8362
8363 switch (expr.type) {
8364 case Syntax.Identifier:
8365 break;
8366 case PlaceHolders.ArrowParameterPlaceHolder:
8367 params = expr.params;
8368 break;
8369 default:
8370 return null;
8371 }
8372
8373 options = {
8374 paramSet: {}
8375 };
8376
8377 for (i = 0, len = params.length; i < len; i += 1) {
8378 param = params[i];
8379 switch (param.type) {
8380 case Syntax.AssignmentPattern:
8381 params[i] = param.left;
8382 if (param.right.type === Syntax.YieldExpression) {
8383 if (param.right.argument) {
8384 throwUnexpectedToken(lookahead);
8385 }
8386 param.right.type = Syntax.Identifier;
8387 param.right.name = 'yield';
8388 delete param.right.argument;
8389 delete param.right.delegate;
8390 }
8391 defaults.push(param.right);
8392 ++defaultCount;
8393 checkPatternParam(options, param.left);
8394 break;
8395 default:
8396 checkPatternParam(options, param);
8397 params[i] = param;
8398 defaults.push(null);
8399 break;
8400 }
8401 }
8402
8403 if (strict || !state.allowYield) {
8404 for (i = 0, len = params.length; i < len; i += 1) {
8405 param = params[i];
8406 if (param.type === Syntax.YieldExpression) {
8407 throwUnexpectedToken(lookahead);
8408 }
8409 }
8410 }
8411
8412 if (options.message === Messages.StrictParamDupe) {
8413 token = strict ? options.stricted : options.firstRestricted;
8414 throwUnexpectedToken(token, options.message);
8415 }
8416
8417 if (defaultCount === 0) {
8418 defaults = [];
8419 }
8420
8421 return {
8422 params: params,
8423 defaults: defaults,
8424 stricted: options.stricted,
8425 firstRestricted: options.firstRestricted,
8426 message: options.message
8427 };
8428 }
8429
8430 function parseArrowFunctionExpression(options, node) {
8431 var previousStrict, previousAllowYield, body;
8432
8433 if (hasLineTerminator) {
8434 tolerateUnexpectedToken(lookahead);
8435 }
8436 expect('=>');
8437
8438 previousStrict = strict;
8439 previousAllowYield = state.allowYield;
8440 state.allowYield = true;
8441
8442 body = parseConciseBody();
8443
8444 if (strict && options.firstRestricted) {
8445 throwUnexpectedToken(options.firstRestricted, options.message);
8446 }
8447 if (strict && options.stricted) {
8448 tolerateUnexpectedToken(options.stricted, options.message);
8449 }
8450
8451 strict = previousStrict;
8452 state.allowYield = previousAllowYield;
8453
8454 return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement);
8455 }
8456
8457 // ECMA-262 14.4 Yield expression
8458
8459 function parseYieldExpression() {
8460 var argument, expr, delegate, previousAllowYield;
8461
8462 argument = null;
8463 expr = new Node();
8464
8465 expectKeyword('yield');
8466
8467 if (!hasLineTerminator) {
8468 previousAllowYield = state.allowYield;
8469 state.allowYield = false;
8470 delegate = match('*');
8471 if (delegate) {
8472 lex();
8473 argument = parseAssignmentExpression();
8474 } else {
8475 if (!match(';') && !match('}') && !match(')') && lookahead.type !== Token.EOF) {
8476 argument = parseAssignmentExpression();
8477 }
8478 }
8479 state.allowYield = previousAllowYield;
8480 }
8481
8482 return expr.finishYieldExpression(argument, delegate);
8483 }
8484
8485 // ECMA-262 12.14 Assignment Operators
8486
8487 function parseAssignmentExpression() {
8488 var token, expr, right, list, startToken;
8489
8490 startToken = lookahead;
8491 token = lookahead;
8492
8493 if (!state.allowYield && matchKeyword('yield')) {
8494 return parseYieldExpression();
8495 }
8496
8497 expr = parseConditionalExpression();
8498
8499 if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) {
8500 isAssignmentTarget = isBindingElement = false;
8501 list = reinterpretAsCoverFormalsList(expr);
8502
8503 if (list) {
8504 firstCoverInitializedNameError = null;
8505 return parseArrowFunctionExpression(list, new WrappingNode(startToken));
8506 }
8507
8508 return expr;
8509 }
8510
8511 if (matchAssign()) {
8512 if (!isAssignmentTarget) {
8513 tolerateError(Messages.InvalidLHSInAssignment);
8514 }
8515
8516 // ECMA-262 12.1.1
8517 if (strict && expr.type === Syntax.Identifier) {
8518 if (isRestrictedWord(expr.name)) {
8519 tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
8520 }
8521 if (isStrictModeReservedWord(expr.name)) {
8522 tolerateUnexpectedToken(token, Messages.StrictReservedWord);
8523 }
8524 }
8525
8526 if (!match('=')) {
8527 isAssignmentTarget = isBindingElement = false;
8528 } else {
8529 reinterpretExpressionAsPattern(expr);
8530 }
8531
8532 token = lex();
8533 right = isolateCoverGrammar(parseAssignmentExpression);
8534 expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right);
8535 firstCoverInitializedNameError = null;
8536 }
8537
8538 return expr;
8539 }
8540
8541 // ECMA-262 12.15 Comma Operator
8542
8543 function parseExpression() {
8544 var expr, startToken = lookahead, expressions;
8545
8546 expr = isolateCoverGrammar(parseAssignmentExpression);
8547
8548 if (match(',')) {
8549 expressions = [expr];
8550
8551 while (startIndex < length) {
8552 if (!match(',')) {
8553 break;
8554 }
8555 lex();
8556 expressions.push(isolateCoverGrammar(parseAssignmentExpression));
8557 }
8558
8559 expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
8560 }
8561
8562 return expr;
8563 }
8564
8565 // ECMA-262 13.2 Block
8566
8567 function parseStatementListItem() {
8568 if (lookahead.type === Token.Keyword) {
8569 switch (lookahead.value) {
8570 case 'export':
8571 if (state.sourceType !== 'module') {
8572 tolerateUnexpectedToken(lookahead, Messages.IllegalExportDeclaration);
8573 }
8574 return parseExportDeclaration();
8575 case 'import':
8576 if (state.sourceType !== 'module') {
8577 tolerateUnexpectedToken(lookahead, Messages.IllegalImportDeclaration);
8578 }
8579 return parseImportDeclaration();
8580 case 'const':
8581 return parseLexicalDeclaration({inFor: false});
8582 case 'function':
8583 return parseFunctionDeclaration(new Node());
8584 case 'class':
8585 return parseClassDeclaration();
8586 }
8587 }
8588
8589 if (matchKeyword('let') && isLexicalDeclaration()) {
8590 return parseLexicalDeclaration({inFor: false});
8591 }
8592
8593 return parseStatement();
8594 }
8595
8596 function parseStatementList() {
8597 var list = [];
8598 while (startIndex < length) {
8599 if (match('}')) {
8600 break;
8601 }
8602 list.push(parseStatementListItem());
8603 }
8604
8605 return list;
8606 }
8607
8608 function parseBlock() {
8609 var block, node = new Node();
8610
8611 expect('{');
8612
8613 block = parseStatementList();
8614
8615 expect('}');
8616
8617 return node.finishBlockStatement(block);
8618 }
8619
8620 // ECMA-262 13.3.2 Variable Statement
8621
8622 function parseVariableIdentifier(kind) {
8623 var token, node = new Node();
8624
8625 token = lex();
8626
8627 if (token.type === Token.Keyword && token.value === 'yield') {
8628 if (strict) {
8629 tolerateUnexpectedToken(token, Messages.StrictReservedWord);
8630 } if (!state.allowYield) {
8631 throwUnexpectedToken(token);
8632 }
8633 } else if (token.type !== Token.Identifier) {
8634 if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) {
8635 tolerateUnexpectedToken(token, Messages.StrictReservedWord);
8636 } else {
8637 if (strict || token.value !== 'let' || kind !== 'var') {
8638 throwUnexpectedToken(token);
8639 }
8640 }
8641 } else if (state.sourceType === 'module' && token.type === Token.Identifier && token.value === 'await') {
8642 tolerateUnexpectedToken(token);
8643 }
8644
8645 return node.finishIdentifier(token.value);
8646 }
8647
8648 function parseVariableDeclaration(options) {
8649 var init = null, id, node = new Node(), params = [];
8650
8651 id = parsePattern(params, 'var');
8652
8653 // ECMA-262 12.2.1
8654 if (strict && isRestrictedWord(id.name)) {
8655 tolerateError(Messages.StrictVarName);
8656 }
8657
8658 if (match('=')) {
8659 lex();
8660 init = isolateCoverGrammar(parseAssignmentExpression);
8661 } else if (id.type !== Syntax.Identifier && !options.inFor) {
8662 expect('=');
8663 }
8664
8665 return node.finishVariableDeclarator(id, init);
8666 }
8667
8668 function parseVariableDeclarationList(options) {
8669 var list = [];
8670
8671 do {
8672 list.push(parseVariableDeclaration({ inFor: options.inFor }));
8673 if (!match(',')) {
8674 break;
8675 }
8676 lex();
8677 } while (startIndex < length);
8678
8679 return list;
8680 }
8681
8682 function parseVariableStatement(node) {
8683 var declarations;
8684
8685 expectKeyword('var');
8686
8687 declarations = parseVariableDeclarationList({ inFor: false });
8688
8689 consumeSemicolon();
8690
8691 return node.finishVariableDeclaration(declarations);
8692 }
8693
8694 // ECMA-262 13.3.1 Let and Const Declarations
8695
8696 function parseLexicalBinding(kind, options) {
8697 var init = null, id, node = new Node(), params = [];
8698
8699 id = parsePattern(params, kind);
8700
8701 // ECMA-262 12.2.1
8702 if (strict && id.type === Syntax.Identifier && isRestrictedWord(id.name)) {
8703 tolerateError(Messages.StrictVarName);
8704 }
8705
8706 if (kind === 'const') {
8707 if (!matchKeyword('in') && !matchContextualKeyword('of')) {
8708 expect('=');
8709 init = isolateCoverGrammar(parseAssignmentExpression);
8710 }
8711 } else if ((!options.inFor && id.type !== Syntax.Identifier) || match('=')) {
8712 expect('=');
8713 init = isolateCoverGrammar(parseAssignmentExpression);
8714 }
8715
8716 return node.finishVariableDeclarator(id, init);
8717 }
8718
8719 function parseBindingList(kind, options) {
8720 var list = [];
8721
8722 do {
8723 list.push(parseLexicalBinding(kind, options));
8724 if (!match(',')) {
8725 break;
8726 }
8727 lex();
8728 } while (startIndex < length);
8729
8730 return list;
8731 }
8732
8733
8734 function tokenizerState() {
8735 return {
8736 index: index,
8737 lineNumber: lineNumber,
8738 lineStart: lineStart,
8739 hasLineTerminator: hasLineTerminator,
8740 lastIndex: lastIndex,
8741 lastLineNumber: lastLineNumber,
8742 lastLineStart: lastLineStart,
8743 startIndex: startIndex,
8744 startLineNumber: startLineNumber,
8745 startLineStart: startLineStart,
8746 lookahead: lookahead,
8747 tokenCount: extra.tokens ? extra.tokens.length : 0
8748 };
8749 }
8750
8751 function resetTokenizerState(ts) {
8752 index = ts.index;
8753 lineNumber = ts.lineNumber;
8754 lineStart = ts.lineStart;
8755 hasLineTerminator = ts.hasLineTerminator;
8756 lastIndex = ts.lastIndex;
8757 lastLineNumber = ts.lastLineNumber;
8758 lastLineStart = ts.lastLineStart;
8759 startIndex = ts.startIndex;
8760 startLineNumber = ts.startLineNumber;
8761 startLineStart = ts.startLineStart;
8762 lookahead = ts.lookahead;
8763 if (extra.tokens) {
8764 extra.tokens.splice(ts.tokenCount, extra.tokens.length);
8765 }
8766 }
8767
8768 function isLexicalDeclaration() {
8769 var lexical, ts;
8770
8771 ts = tokenizerState();
8772
8773 lex();
8774 lexical = (lookahead.type === Token.Identifier) || match('[') || match('{') ||
8775 matchKeyword('let') || matchKeyword('yield');
8776
8777 resetTokenizerState(ts);
8778
8779 return lexical;
8780 }
8781
8782 function parseLexicalDeclaration(options) {
8783 var kind, declarations, node = new Node();
8784
8785 kind = lex().value;
8786 assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');
8787
8788 declarations = parseBindingList(kind, options);
8789
8790 consumeSemicolon();
8791
8792 return node.finishLexicalDeclaration(declarations, kind);
8793 }
8794
8795 function parseRestElement(params) {
8796 var param, node = new Node();
8797
8798 lex();
8799
8800 if (match('{')) {
8801 throwError(Messages.ObjectPatternAsRestParameter);
8802 }
8803
8804 params.push(lookahead);
8805
8806 param = parseVariableIdentifier();
8807
8808 if (match('=')) {
8809 throwError(Messages.DefaultRestParameter);
8810 }
8811
8812 if (!match(')')) {
8813 throwError(Messages.ParameterAfterRestParameter);
8814 }
8815
8816 return node.finishRestElement(param);
8817 }
8818
8819 // ECMA-262 13.4 Empty Statement
8820
8821 function parseEmptyStatement(node) {
8822 expect(';');
8823 return node.finishEmptyStatement();
8824 }
8825
8826 // ECMA-262 12.4 Expression Statement
8827
8828 function parseExpressionStatement(node) {
8829 var expr = parseExpression();
8830 consumeSemicolon();
8831 return node.finishExpressionStatement(expr);
8832 }
8833
8834 // ECMA-262 13.6 If statement
8835
8836 function parseIfStatement(node) {
8837 var test, consequent, alternate;
8838
8839 expectKeyword('if');
8840
8841 expect('(');
8842
8843 test = parseExpression();
8844
8845 expect(')');
8846
8847 consequent = parseStatement();
8848
8849 if (matchKeyword('else')) {
8850 lex();
8851 alternate = parseStatement();
8852 } else {
8853 alternate = null;
8854 }
8855
8856 return node.finishIfStatement(test, consequent, alternate);
8857 }
8858
8859 // ECMA-262 13.7 Iteration Statements
8860
8861 function parseDoWhileStatement(node) {
8862 var body, test, oldInIteration;
8863
8864 expectKeyword('do');
8865
8866 oldInIteration = state.inIteration;
8867 state.inIteration = true;
8868
8869 body = parseStatement();
8870
8871 state.inIteration = oldInIteration;
8872
8873 expectKeyword('while');
8874
8875 expect('(');
8876
8877 test = parseExpression();
8878
8879 expect(')');
8880
8881 if (match(';')) {
8882 lex();
8883 }
8884
8885 return node.finishDoWhileStatement(body, test);
8886 }
8887
8888 function parseWhileStatement(node) {
8889 var test, body, oldInIteration;
8890
8891 expectKeyword('while');
8892
8893 expect('(');
8894
8895 test = parseExpression();
8896
8897 expect(')');
8898
8899 oldInIteration = state.inIteration;
8900 state.inIteration = true;
8901
8902 body = parseStatement();
8903
8904 state.inIteration = oldInIteration;
8905
8906 return node.finishWhileStatement(test, body);
8907 }
8908
8909 function parseForStatement(node) {
8910 var init, forIn, initSeq, initStartToken, test, update, left, right, kind, declarations,
8911 body, oldInIteration, previousAllowIn = state.allowIn;
8912
8913 init = test = update = null;
8914 forIn = true;
8915
8916 expectKeyword('for');
8917
8918 expect('(');
8919
8920 if (match(';')) {
8921 lex();
8922 } else {
8923 if (matchKeyword('var')) {
8924 init = new Node();
8925 lex();
8926
8927 state.allowIn = false;
8928 declarations = parseVariableDeclarationList({ inFor: true });
8929 state.allowIn = previousAllowIn;
8930
8931 if (declarations.length === 1 && matchKeyword('in')) {
8932 init = init.finishVariableDeclaration(declarations);
8933 lex();
8934 left = init;
8935 right = parseExpression();
8936 init = null;
8937 } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) {
8938 init = init.finishVariableDeclaration(declarations);
8939 lex();
8940 left = init;
8941 right = parseAssignmentExpression();
8942 init = null;
8943 forIn = false;
8944 } else {
8945 init = init.finishVariableDeclaration(declarations);
8946 expect(';');
8947 }
8948 } else if (matchKeyword('const') || matchKeyword('let')) {
8949 init = new Node();
8950 kind = lex().value;
8951
8952 if (!strict && lookahead.value === 'in') {
8953 init = init.finishIdentifier(kind);
8954 lex();
8955 left = init;
8956 right = parseExpression();
8957 init = null;
8958 } else {
8959 state.allowIn = false;
8960 declarations = parseBindingList(kind, {inFor: true});
8961 state.allowIn = previousAllowIn;
8962
8963 if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) {
8964 init = init.finishLexicalDeclaration(declarations, kind);
8965 lex();
8966 left = init;
8967 right = parseExpression();
8968 init = null;
8969 } else if (declarations.length === 1 && declarations[0].init === null && matchContextualKeyword('of')) {
8970 init = init.finishLexicalDeclaration(declarations, kind);
8971 lex();
8972 left = init;
8973 right = parseAssignmentExpression();
8974 init = null;
8975 forIn = false;
8976 } else {
8977 consumeSemicolon();
8978 init = init.finishLexicalDeclaration(declarations, kind);
8979 }
8980 }
8981 } else {
8982 initStartToken = lookahead;
8983 state.allowIn = false;
8984 init = inheritCoverGrammar(parseAssignmentExpression);
8985 state.allowIn = previousAllowIn;
8986
8987 if (matchKeyword('in')) {
8988 if (!isAssignmentTarget) {
8989 tolerateError(Messages.InvalidLHSInForIn);
8990 }
8991
8992 lex();
8993 reinterpretExpressionAsPattern(init);
8994 left = init;
8995 right = parseExpression();
8996 init = null;
8997 } else if (matchContextualKeyword('of')) {
8998 if (!isAssignmentTarget) {
8999 tolerateError(Messages.InvalidLHSInForLoop);
9000 }
9001
9002 lex();
9003 reinterpretExpressionAsPattern(init);
9004 left = init;
9005 right = parseAssignmentExpression();
9006 init = null;
9007 forIn = false;
9008 } else {
9009 if (match(',')) {
9010 initSeq = [init];
9011 while (match(',')) {
9012 lex();
9013 initSeq.push(isolateCoverGrammar(parseAssignmentExpression));
9014 }
9015 init = new WrappingNode(initStartToken).finishSequenceExpression(initSeq);
9016 }
9017 expect(';');
9018 }
9019 }
9020 }
9021
9022 if (typeof left === 'undefined') {
9023
9024 if (!match(';')) {
9025 test = parseExpression();
9026 }
9027 expect(';');
9028
9029 if (!match(')')) {
9030 update = parseExpression();
9031 }
9032 }
9033
9034 expect(')');
9035
9036 oldInIteration = state.inIteration;
9037 state.inIteration = true;
9038
9039 body = isolateCoverGrammar(parseStatement);
9040
9041 state.inIteration = oldInIteration;
9042
9043 return (typeof left === 'undefined') ?
9044 node.finishForStatement(init, test, update, body) :
9045 forIn ? node.finishForInStatement(left, right, body) :
9046 node.finishForOfStatement(left, right, body);
9047 }
9048
9049 // ECMA-262 13.8 The continue statement
9050
9051 function parseContinueStatement(node) {
9052 var label = null, key;
9053
9054 expectKeyword('continue');
9055
9056 // Optimize the most common form: 'continue;'.
9057 if (source.charCodeAt(startIndex) === 0x3B) {
9058 lex();
9059
9060 if (!state.inIteration) {
9061 throwError(Messages.IllegalContinue);
9062 }
9063
9064 return node.finishContinueStatement(null);
9065 }
9066
9067 if (hasLineTerminator) {
9068 if (!state.inIteration) {
9069 throwError(Messages.IllegalContinue);
9070 }
9071
9072 return node.finishContinueStatement(null);
9073 }
9074
9075 if (lookahead.type === Token.Identifier) {
9076 label = parseVariableIdentifier();
9077
9078 key = '$' + label.name;
9079 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
9080 throwError(Messages.UnknownLabel, label.name);
9081 }
9082 }
9083
9084 consumeSemicolon();
9085
9086 if (label === null && !state.inIteration) {
9087 throwError(Messages.IllegalContinue);
9088 }
9089
9090 return node.finishContinueStatement(label);
9091 }
9092
9093 // ECMA-262 13.9 The break statement
9094
9095 function parseBreakStatement(node) {
9096 var label = null, key;
9097
9098 expectKeyword('break');
9099
9100 // Catch the very common case first: immediately a semicolon (U+003B).
9101 if (source.charCodeAt(lastIndex) === 0x3B) {
9102 lex();
9103
9104 if (!(state.inIteration || state.inSwitch)) {
9105 throwError(Messages.IllegalBreak);
9106 }
9107
9108 return node.finishBreakStatement(null);
9109 }
9110
9111 if (hasLineTerminator) {
9112 if (!(state.inIteration || state.inSwitch)) {
9113 throwError(Messages.IllegalBreak);
9114 }
9115 } else if (lookahead.type === Token.Identifier) {
9116 label = parseVariableIdentifier();
9117
9118 key = '$' + label.name;
9119 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
9120 throwError(Messages.UnknownLabel, label.name);
9121 }
9122 }
9123
9124 consumeSemicolon();
9125
9126 if (label === null && !(state.inIteration || state.inSwitch)) {
9127 throwError(Messages.IllegalBreak);
9128 }
9129
9130 return node.finishBreakStatement(label);
9131 }
9132
9133 // ECMA-262 13.10 The return statement
9134
9135 function parseReturnStatement(node) {
9136 var argument = null;
9137
9138 expectKeyword('return');
9139
9140 if (!state.inFunctionBody) {
9141 tolerateError(Messages.IllegalReturn);
9142 }
9143
9144 // 'return' followed by a space and an identifier is very common.
9145 if (source.charCodeAt(lastIndex) === 0x20) {
9146 if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) {
9147 argument = parseExpression();
9148 consumeSemicolon();
9149 return node.finishReturnStatement(argument);
9150 }
9151 }
9152
9153 if (hasLineTerminator) {
9154 // HACK
9155 return node.finishReturnStatement(null);
9156 }
9157
9158 if (!match(';')) {
9159 if (!match('}') && lookahead.type !== Token.EOF) {
9160 argument = parseExpression();
9161 }
9162 }
9163
9164 consumeSemicolon();
9165
9166 return node.finishReturnStatement(argument);
9167 }
9168
9169 // ECMA-262 13.11 The with statement
9170
9171 function parseWithStatement(node) {
9172 var object, body;
9173
9174 if (strict) {
9175 tolerateError(Messages.StrictModeWith);
9176 }
9177
9178 expectKeyword('with');
9179
9180 expect('(');
9181
9182 object = parseExpression();
9183
9184 expect(')');
9185
9186 body = parseStatement();
9187
9188 return node.finishWithStatement(object, body);
9189 }
9190
9191 // ECMA-262 13.12 The switch statement
9192
9193 function parseSwitchCase() {
9194 var test, consequent = [], statement, node = new Node();
9195
9196 if (matchKeyword('default')) {
9197 lex();
9198 test = null;
9199 } else {
9200 expectKeyword('case');
9201 test = parseExpression();
9202 }
9203 expect(':');
9204
9205 while (startIndex < length) {
9206 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
9207 break;
9208 }
9209 statement = parseStatementListItem();
9210 consequent.push(statement);
9211 }
9212
9213 return node.finishSwitchCase(test, consequent);
9214 }
9215
9216 function parseSwitchStatement(node) {
9217 var discriminant, cases, clause, oldInSwitch, defaultFound;
9218
9219 expectKeyword('switch');
9220
9221 expect('(');
9222
9223 discriminant = parseExpression();
9224
9225 expect(')');
9226
9227 expect('{');
9228
9229 cases = [];
9230
9231 if (match('}')) {
9232 lex();
9233 return node.finishSwitchStatement(discriminant, cases);
9234 }
9235
9236 oldInSwitch = state.inSwitch;
9237 state.inSwitch = true;
9238 defaultFound = false;
9239
9240 while (startIndex < length) {
9241 if (match('}')) {
9242 break;
9243 }
9244 clause = parseSwitchCase();
9245 if (clause.test === null) {
9246 if (defaultFound) {
9247 throwError(Messages.MultipleDefaultsInSwitch);
9248 }
9249 defaultFound = true;
9250 }
9251 cases.push(clause);
9252 }
9253
9254 state.inSwitch = oldInSwitch;
9255
9256 expect('}');
9257
9258 return node.finishSwitchStatement(discriminant, cases);
9259 }
9260
9261 // ECMA-262 13.14 The throw statement
9262
9263 function parseThrowStatement(node) {
9264 var argument;
9265
9266 expectKeyword('throw');
9267
9268 if (hasLineTerminator) {
9269 throwError(Messages.NewlineAfterThrow);
9270 }
9271
9272 argument = parseExpression();
9273
9274 consumeSemicolon();
9275
9276 return node.finishThrowStatement(argument);
9277 }
9278
9279 // ECMA-262 13.15 The try statement
9280
9281 function parseCatchClause() {
9282 var param, params = [], paramMap = {}, key, i, body, node = new Node();
9283
9284 expectKeyword('catch');
9285
9286 expect('(');
9287 if (match(')')) {
9288 throwUnexpectedToken(lookahead);
9289 }
9290
9291 param = parsePattern(params);
9292 for (i = 0; i < params.length; i++) {
9293 key = '$' + params[i].value;
9294 if (Object.prototype.hasOwnProperty.call(paramMap, key)) {
9295 tolerateError(Messages.DuplicateBinding, params[i].value);
9296 }
9297 paramMap[key] = true;
9298 }
9299
9300 // ECMA-262 12.14.1
9301 if (strict && isRestrictedWord(param.name)) {
9302 tolerateError(Messages.StrictCatchVariable);
9303 }
9304
9305 expect(')');
9306 body = parseBlock();
9307 return node.finishCatchClause(param, body);
9308 }
9309
9310 function parseTryStatement(node) {
9311 var block, handler = null, finalizer = null;
9312
9313 expectKeyword('try');
9314
9315 block = parseBlock();
9316
9317 if (matchKeyword('catch')) {
9318 handler = parseCatchClause();
9319 }
9320
9321 if (matchKeyword('finally')) {
9322 lex();
9323 finalizer = parseBlock();
9324 }
9325
9326 if (!handler && !finalizer) {
9327 throwError(Messages.NoCatchOrFinally);
9328 }
9329
9330 return node.finishTryStatement(block, handler, finalizer);
9331 }
9332
9333 // ECMA-262 13.16 The debugger statement
9334
9335 function parseDebuggerStatement(node) {
9336 expectKeyword('debugger');
9337
9338 consumeSemicolon();
9339
9340 return node.finishDebuggerStatement();
9341 }
9342
9343 // 13 Statements
9344
9345 function parseStatement() {
9346 var type = lookahead.type,
9347 expr,
9348 labeledBody,
9349 key,
9350 node;
9351
9352 if (type === Token.EOF) {
9353 throwUnexpectedToken(lookahead);
9354 }
9355
9356 if (type === Token.Punctuator && lookahead.value === '{') {
9357 return parseBlock();
9358 }
9359 isAssignmentTarget = isBindingElement = true;
9360 node = new Node();
9361
9362 if (type === Token.Punctuator) {
9363 switch (lookahead.value) {
9364 case ';':
9365 return parseEmptyStatement(node);
9366 case '(':
9367 return parseExpressionStatement(node);
9368 default:
9369 break;
9370 }
9371 } else if (type === Token.Keyword) {
9372 switch (lookahead.value) {
9373 case 'break':
9374 return parseBreakStatement(node);
9375 case 'continue':
9376 return parseContinueStatement(node);
9377 case 'debugger':
9378 return parseDebuggerStatement(node);
9379 case 'do':
9380 return parseDoWhileStatement(node);
9381 case 'for':
9382 return parseForStatement(node);
9383 case 'function':
9384 return parseFunctionDeclaration(node);
9385 case 'if':
9386 return parseIfStatement(node);
9387 case 'return':
9388 return parseReturnStatement(node);
9389 case 'switch':
9390 return parseSwitchStatement(node);
9391 case 'throw':
9392 return parseThrowStatement(node);
9393 case 'try':
9394 return parseTryStatement(node);
9395 case 'var':
9396 return parseVariableStatement(node);
9397 case 'while':
9398 return parseWhileStatement(node);
9399 case 'with':
9400 return parseWithStatement(node);
9401 default:
9402 break;
9403 }
9404 }
9405
9406 expr = parseExpression();
9407
9408 // ECMA-262 12.12 Labelled Statements
9409 if ((expr.type === Syntax.Identifier) && match(':')) {
9410 lex();
9411
9412 key = '$' + expr.name;
9413 if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
9414 throwError(Messages.Redeclaration, 'Label', expr.name);
9415 }
9416
9417 state.labelSet[key] = true;
9418 labeledBody = parseStatement();
9419 delete state.labelSet[key];
9420 return node.finishLabeledStatement(expr, labeledBody);
9421 }
9422
9423 consumeSemicolon();
9424
9425 return node.finishExpressionStatement(expr);
9426 }
9427
9428 // ECMA-262 14.1 Function Definition
9429
9430 function parseFunctionSourceElements() {
9431 var statement, body = [], token, directive, firstRestricted,
9432 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount,
9433 node = new Node();
9434
9435 expect('{');
9436
9437 while (startIndex < length) {
9438 if (lookahead.type !== Token.StringLiteral) {
9439 break;
9440 }
9441 token = lookahead;
9442
9443 statement = parseStatementListItem();
9444 body.push(statement);
9445 if (statement.expression.type !== Syntax.Literal) {
9446 // this is not directive
9447 break;
9448 }
9449 directive = source.slice(token.start + 1, token.end - 1);
9450 if (directive === 'use strict') {
9451 strict = true;
9452 if (firstRestricted) {
9453 tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
9454 }
9455 } else {
9456 if (!firstRestricted && token.octal) {
9457 firstRestricted = token;
9458 }
9459 }
9460 }
9461
9462 oldLabelSet = state.labelSet;
9463 oldInIteration = state.inIteration;
9464 oldInSwitch = state.inSwitch;
9465 oldInFunctionBody = state.inFunctionBody;
9466 oldParenthesisCount = state.parenthesizedCount;
9467
9468 state.labelSet = {};
9469 state.inIteration = false;
9470 state.inSwitch = false;
9471 state.inFunctionBody = true;
9472 state.parenthesizedCount = 0;
9473
9474 while (startIndex < length) {
9475 if (match('}')) {
9476 break;
9477 }
9478 body.push(parseStatementListItem());
9479 }
9480
9481 expect('}');
9482
9483 state.labelSet = oldLabelSet;
9484 state.inIteration = oldInIteration;
9485 state.inSwitch = oldInSwitch;
9486 state.inFunctionBody = oldInFunctionBody;
9487 state.parenthesizedCount = oldParenthesisCount;
9488
9489 return node.finishBlockStatement(body);
9490 }
9491
9492 function validateParam(options, param, name) {
9493 var key = '$' + name;
9494 if (strict) {
9495 if (isRestrictedWord(name)) {
9496 options.stricted = param;
9497 options.message = Messages.StrictParamName;
9498 }
9499 if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
9500 options.stricted = param;
9501 options.message = Messages.StrictParamDupe;
9502 }
9503 } else if (!options.firstRestricted) {
9504 if (isRestrictedWord(name)) {
9505 options.firstRestricted = param;
9506 options.message = Messages.StrictParamName;
9507 } else if (isStrictModeReservedWord(name)) {
9508 options.firstRestricted = param;
9509 options.message = Messages.StrictReservedWord;
9510 } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
9511 options.stricted = param;
9512 options.message = Messages.StrictParamDupe;
9513 }
9514 }
9515 options.paramSet[key] = true;
9516 }
9517
9518 function parseParam(options) {
9519 var token, param, params = [], i, def;
9520
9521 token = lookahead;
9522 if (token.value === '...') {
9523 param = parseRestElement(params);
9524 validateParam(options, param.argument, param.argument.name);
9525 options.params.push(param);
9526 options.defaults.push(null);
9527 return false;
9528 }
9529
9530 param = parsePatternWithDefault(params);
9531 for (i = 0; i < params.length; i++) {
9532 validateParam(options, params[i], params[i].value);
9533 }
9534
9535 if (param.type === Syntax.AssignmentPattern) {
9536 def = param.right;
9537 param = param.left;
9538 ++options.defaultCount;
9539 }
9540
9541 options.params.push(param);
9542 options.defaults.push(def);
9543
9544 return !match(')');
9545 }
9546
9547 function parseParams(firstRestricted) {
9548 var options;
9549
9550 options = {
9551 params: [],
9552 defaultCount: 0,
9553 defaults: [],
9554 firstRestricted: firstRestricted
9555 };
9556
9557 expect('(');
9558
9559 if (!match(')')) {
9560 options.paramSet = {};
9561 while (startIndex < length) {
9562 if (!parseParam(options)) {
9563 break;
9564 }
9565 expect(',');
9566 }
9567 }
9568
9569 expect(')');
9570
9571 if (options.defaultCount === 0) {
9572 options.defaults = [];
9573 }
9574
9575 return {
9576 params: options.params,
9577 defaults: options.defaults,
9578 stricted: options.stricted,
9579 firstRestricted: options.firstRestricted,
9580 message: options.message
9581 };
9582 }
9583
9584 function parseFunctionDeclaration(node, identifierIsOptional) {
9585 var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict,
9586 isGenerator, previousAllowYield;
9587
9588 previousAllowYield = state.allowYield;
9589
9590 expectKeyword('function');
9591
9592 isGenerator = match('*');
9593 if (isGenerator) {
9594 lex();
9595 }
9596
9597 if (!identifierIsOptional || !match('(')) {
9598 token = lookahead;
9599 id = parseVariableIdentifier();
9600 if (strict) {
9601 if (isRestrictedWord(token.value)) {
9602 tolerateUnexpectedToken(token, Messages.StrictFunctionName);
9603 }
9604 } else {
9605 if (isRestrictedWord(token.value)) {
9606 firstRestricted = token;
9607 message = Messages.StrictFunctionName;
9608 } else if (isStrictModeReservedWord(token.value)) {
9609 firstRestricted = token;
9610 message = Messages.StrictReservedWord;
9611 }
9612 }
9613 }
9614
9615 state.allowYield = !isGenerator;
9616 tmp = parseParams(firstRestricted);
9617 params = tmp.params;
9618 defaults = tmp.defaults;
9619 stricted = tmp.stricted;
9620 firstRestricted = tmp.firstRestricted;
9621 if (tmp.message) {
9622 message = tmp.message;
9623 }
9624
9625
9626 previousStrict = strict;
9627 body = parseFunctionSourceElements();
9628 if (strict && firstRestricted) {
9629 throwUnexpectedToken(firstRestricted, message);
9630 }
9631 if (strict && stricted) {
9632 tolerateUnexpectedToken(stricted, message);
9633 }
9634
9635 strict = previousStrict;
9636 state.allowYield = previousAllowYield;
9637
9638 return node.finishFunctionDeclaration(id, params, defaults, body, isGenerator);
9639 }
9640
9641 function parseFunctionExpression() {
9642 var token, id = null, stricted, firstRestricted, message, tmp,
9643 params = [], defaults = [], body, previousStrict, node = new Node(),
9644 isGenerator, previousAllowYield;
9645
9646 previousAllowYield = state.allowYield;
9647
9648 expectKeyword('function');
9649
9650 isGenerator = match('*');
9651 if (isGenerator) {
9652 lex();
9653 }
9654
9655 state.allowYield = !isGenerator;
9656 if (!match('(')) {
9657 token = lookahead;
9658 id = (!strict && !isGenerator && matchKeyword('yield')) ? parseNonComputedProperty() : parseVariableIdentifier();
9659 if (strict) {
9660 if (isRestrictedWord(token.value)) {
9661 tolerateUnexpectedToken(token, Messages.StrictFunctionName);
9662 }
9663 } else {
9664 if (isRestrictedWord(token.value)) {
9665 firstRestricted = token;
9666 message = Messages.StrictFunctionName;
9667 } else if (isStrictModeReservedWord(token.value)) {
9668 firstRestricted = token;
9669 message = Messages.StrictReservedWord;
9670 }
9671 }
9672 }
9673
9674 tmp = parseParams(firstRestricted);
9675 params = tmp.params;
9676 defaults = tmp.defaults;
9677 stricted = tmp.stricted;
9678 firstRestricted = tmp.firstRestricted;
9679 if (tmp.message) {
9680 message = tmp.message;
9681 }
9682
9683 previousStrict = strict;
9684 body = parseFunctionSourceElements();
9685 if (strict && firstRestricted) {
9686 throwUnexpectedToken(firstRestricted, message);
9687 }
9688 if (strict && stricted) {
9689 tolerateUnexpectedToken(stricted, message);
9690 }
9691 strict = previousStrict;
9692 state.allowYield = previousAllowYield;
9693
9694 return node.finishFunctionExpression(id, params, defaults, body, isGenerator);
9695 }
9696
9697 // ECMA-262 14.5 Class Definitions
9698
9699 function parseClassBody() {
9700 var classBody, token, isStatic, hasConstructor = false, body, method, computed, key;
9701
9702 classBody = new Node();
9703
9704 expect('{');
9705 body = [];
9706 while (!match('}')) {
9707 if (match(';')) {
9708 lex();
9709 } else {
9710 method = new Node();
9711 token = lookahead;
9712 isStatic = false;
9713 computed = match('[');
9714 if (match('*')) {
9715 lex();
9716 } else {
9717 key = parseObjectPropertyKey();
9718 if (key.name === 'static' && (lookaheadPropertyName() || match('*'))) {
9719 token = lookahead;
9720 isStatic = true;
9721 computed = match('[');
9722 if (match('*')) {
9723 lex();
9724 } else {
9725 key = parseObjectPropertyKey();
9726 }
9727 }
9728 }
9729 method = tryParseMethodDefinition(token, key, computed, method);
9730 if (method) {
9731 method['static'] = isStatic; // jscs:ignore requireDotNotation
9732 if (method.kind === 'init') {
9733 method.kind = 'method';
9734 }
9735 if (!isStatic) {
9736 if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') {
9737 if (method.kind !== 'method' || !method.method || method.value.generator) {
9738 throwUnexpectedToken(token, Messages.ConstructorSpecialMethod);
9739 }
9740 if (hasConstructor) {
9741 throwUnexpectedToken(token, Messages.DuplicateConstructor);
9742 } else {
9743 hasConstructor = true;
9744 }
9745 method.kind = 'constructor';
9746 }
9747 } else {
9748 if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') {
9749 throwUnexpectedToken(token, Messages.StaticPrototype);
9750 }
9751 }
9752 method.type = Syntax.MethodDefinition;
9753 delete method.method;
9754 delete method.shorthand;
9755 body.push(method);
9756 } else {
9757 throwUnexpectedToken(lookahead);
9758 }
9759 }
9760 }
9761 lex();
9762 return classBody.finishClassBody(body);
9763 }
9764
9765 function parseClassDeclaration(identifierIsOptional) {
9766 var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
9767 strict = true;
9768
9769 expectKeyword('class');
9770
9771 if (!identifierIsOptional || lookahead.type === Token.Identifier) {
9772 id = parseVariableIdentifier();
9773 }
9774
9775 if (matchKeyword('extends')) {
9776 lex();
9777 superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
9778 }
9779 classBody = parseClassBody();
9780 strict = previousStrict;
9781
9782 return classNode.finishClassDeclaration(id, superClass, classBody);
9783 }
9784
9785 function parseClassExpression() {
9786 var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
9787 strict = true;
9788
9789 expectKeyword('class');
9790
9791 if (lookahead.type === Token.Identifier) {
9792 id = parseVariableIdentifier();
9793 }
9794
9795 if (matchKeyword('extends')) {
9796 lex();
9797 superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
9798 }
9799 classBody = parseClassBody();
9800 strict = previousStrict;
9801
9802 return classNode.finishClassExpression(id, superClass, classBody);
9803 }
9804
9805 // ECMA-262 15.2 Modules
9806
9807 function parseModuleSpecifier() {
9808 var node = new Node();
9809
9810 if (lookahead.type !== Token.StringLiteral) {
9811 throwError(Messages.InvalidModuleSpecifier);
9812 }
9813 return node.finishLiteral(lex());
9814 }
9815
9816 // ECMA-262 15.2.3 Exports
9817
9818 function parseExportSpecifier() {
9819 var exported, local, node = new Node(), def;
9820 if (matchKeyword('default')) {
9821 // export {default} from 'something';
9822 def = new Node();
9823 lex();
9824 local = def.finishIdentifier('default');
9825 } else {
9826 local = parseVariableIdentifier();
9827 }
9828 if (matchContextualKeyword('as')) {
9829 lex();
9830 exported = parseNonComputedProperty();
9831 }
9832 return node.finishExportSpecifier(local, exported);
9833 }
9834
9835 function parseExportNamedDeclaration(node) {
9836 var declaration = null,
9837 isExportFromIdentifier,
9838 src = null, specifiers = [];
9839
9840 // non-default export
9841 if (lookahead.type === Token.Keyword) {
9842 // covers:
9843 // export var f = 1;
9844 switch (lookahead.value) {
9845 case 'let':
9846 case 'const':
9847 declaration = parseLexicalDeclaration({inFor: false});
9848 return node.finishExportNamedDeclaration(declaration, specifiers, null);
9849 case 'var':
9850 case 'class':
9851 case 'function':
9852 declaration = parseStatementListItem();
9853 return node.finishExportNamedDeclaration(declaration, specifiers, null);
9854 }
9855 }
9856
9857 expect('{');
9858 while (!match('}')) {
9859 isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default');
9860 specifiers.push(parseExportSpecifier());
9861 if (!match('}')) {
9862 expect(',');
9863 if (match('}')) {
9864 break;
9865 }
9866 }
9867 }
9868 expect('}');
9869
9870 if (matchContextualKeyword('from')) {
9871 // covering:
9872 // export {default} from 'foo';
9873 // export {foo} from 'foo';
9874 lex();
9875 src = parseModuleSpecifier();
9876 consumeSemicolon();
9877 } else if (isExportFromIdentifier) {
9878 // covering:
9879 // export {default}; // missing fromClause
9880 throwError(lookahead.value ?
9881 Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
9882 } else {
9883 // cover
9884 // export {foo};
9885 consumeSemicolon();
9886 }
9887 return node.finishExportNamedDeclaration(declaration, specifiers, src);
9888 }
9889
9890 function parseExportDefaultDeclaration(node) {
9891 var declaration = null,
9892 expression = null;
9893
9894 // covers:
9895 // export default ...
9896 expectKeyword('default');
9897
9898 if (matchKeyword('function')) {
9899 // covers:
9900 // export default function foo () {}
9901 // export default function () {}
9902 declaration = parseFunctionDeclaration(new Node(), true);
9903 return node.finishExportDefaultDeclaration(declaration);
9904 }
9905 if (matchKeyword('class')) {
9906 declaration = parseClassDeclaration(true);
9907 return node.finishExportDefaultDeclaration(declaration);
9908 }
9909
9910 if (matchContextualKeyword('from')) {
9911 throwError(Messages.UnexpectedToken, lookahead.value);
9912 }
9913
9914 // covers:
9915 // export default {};
9916 // export default [];
9917 // export default (1 + 2);
9918 if (match('{')) {
9919 expression = parseObjectInitializer();
9920 } else if (match('[')) {
9921 expression = parseArrayInitializer();
9922 } else {
9923 expression = parseAssignmentExpression();
9924 }
9925 consumeSemicolon();
9926 return node.finishExportDefaultDeclaration(expression);
9927 }
9928
9929 function parseExportAllDeclaration(node) {
9930 var src;
9931
9932 // covers:
9933 // export * from 'foo';
9934 expect('*');
9935 if (!matchContextualKeyword('from')) {
9936 throwError(lookahead.value ?
9937 Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
9938 }
9939 lex();
9940 src = parseModuleSpecifier();
9941 consumeSemicolon();
9942
9943 return node.finishExportAllDeclaration(src);
9944 }
9945
9946 function parseExportDeclaration() {
9947 var node = new Node();
9948 if (state.inFunctionBody) {
9949 throwError(Messages.IllegalExportDeclaration);
9950 }
9951
9952 expectKeyword('export');
9953
9954 if (matchKeyword('default')) {
9955 return parseExportDefaultDeclaration(node);
9956 }
9957 if (match('*')) {
9958 return parseExportAllDeclaration(node);
9959 }
9960 return parseExportNamedDeclaration(node);
9961 }
9962
9963 // ECMA-262 15.2.2 Imports
9964
9965 function parseImportSpecifier() {
9966 // import {<foo as bar>} ...;
9967 var local, imported, node = new Node();
9968
9969 imported = parseNonComputedProperty();
9970 if (matchContextualKeyword('as')) {
9971 lex();
9972 local = parseVariableIdentifier();
9973 }
9974
9975 return node.finishImportSpecifier(local, imported);
9976 }
9977
9978 function parseNamedImports() {
9979 var specifiers = [];
9980 // {foo, bar as bas}
9981 expect('{');
9982 while (!match('}')) {
9983 specifiers.push(parseImportSpecifier());
9984 if (!match('}')) {
9985 expect(',');
9986 if (match('}')) {
9987 break;
9988 }
9989 }
9990 }
9991 expect('}');
9992 return specifiers;
9993 }
9994
9995 function parseImportDefaultSpecifier() {
9996 // import <foo> ...;
9997 var local, node = new Node();
9998
9999 local = parseNonComputedProperty();
10000
10001 return node.finishImportDefaultSpecifier(local);
10002 }
10003
10004 function parseImportNamespaceSpecifier() {
10005 // import <* as foo> ...;
10006 var local, node = new Node();
10007
10008 expect('*');
10009 if (!matchContextualKeyword('as')) {
10010 throwError(Messages.NoAsAfterImportNamespace);
10011 }
10012 lex();
10013 local = parseNonComputedProperty();
10014
10015 return node.finishImportNamespaceSpecifier(local);
10016 }
10017
10018 function parseImportDeclaration() {
10019 var specifiers = [], src, node = new Node();
10020
10021 if (state.inFunctionBody) {
10022 throwError(Messages.IllegalImportDeclaration);
10023 }
10024
10025 expectKeyword('import');
10026
10027 if (lookahead.type === Token.StringLiteral) {
10028 // import 'foo';
10029 src = parseModuleSpecifier();
10030 } else {
10031
10032 if (match('{')) {
10033 // import {bar}
10034 specifiers = specifiers.concat(parseNamedImports());
10035 } else if (match('*')) {
10036 // import * as foo
10037 specifiers.push(parseImportNamespaceSpecifier());
10038 } else if (isIdentifierName(lookahead) && !matchKeyword('default')) {
10039 // import foo
10040 specifiers.push(parseImportDefaultSpecifier());
10041 if (match(',')) {
10042 lex();
10043 if (match('*')) {
10044 // import foo, * as foo
10045 specifiers.push(parseImportNamespaceSpecifier());
10046 } else if (match('{')) {
10047 // import foo, {bar}
10048 specifiers = specifiers.concat(parseNamedImports());
10049 } else {
10050 throwUnexpectedToken(lookahead);
10051 }
10052 }
10053 } else {
10054 throwUnexpectedToken(lex());
10055 }
10056
10057 if (!matchContextualKeyword('from')) {
10058 throwError(lookahead.value ?
10059 Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
10060 }
10061 lex();
10062 src = parseModuleSpecifier();
10063 }
10064
10065 consumeSemicolon();
10066 return node.finishImportDeclaration(specifiers, src);
10067 }
10068
10069 // ECMA-262 15.1 Scripts
10070
10071 function parseScriptBody() {
10072 var statement, body = [], token, directive, firstRestricted;
10073
10074 while (startIndex < length) {
10075 token = lookahead;
10076 if (token.type !== Token.StringLiteral) {
10077 break;
10078 }
10079
10080 statement = parseStatementListItem();
10081 body.push(statement);
10082 if (statement.expression.type !== Syntax.Literal) {
10083 // this is not directive
10084 break;
10085 }
10086 directive = source.slice(token.start + 1, token.end - 1);
10087 if (directive === 'use strict') {
10088 strict = true;
10089 if (firstRestricted) {
10090 tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
10091 }
10092 } else {
10093 if (!firstRestricted && token.octal) {
10094 firstRestricted = token;
10095 }
10096 }
10097 }
10098
10099 while (startIndex < length) {
10100 statement = parseStatementListItem();
10101 /* istanbul ignore if */
10102 if (typeof statement === 'undefined') {
10103 break;
10104 }
10105 body.push(statement);
10106 }
10107 return body;
10108 }
10109
10110 function parseProgram() {
10111 var body, node;
10112
10113 peek();
10114 node = new Node();
10115
10116 body = parseScriptBody();
10117 return node.finishProgram(body, state.sourceType);
10118 }
10119
10120 function filterTokenLocation() {
10121 var i, entry, token, tokens = [];
10122
10123 for (i = 0; i < extra.tokens.length; ++i) {
10124 entry = extra.tokens[i];
10125 token = {
10126 type: entry.type,
10127 value: entry.value
10128 };
10129 if (entry.regex) {
10130 token.regex = {
10131 pattern: entry.regex.pattern,
10132 flags: entry.regex.flags
10133 };
10134 }
10135 if (extra.range) {
10136 token.range = entry.range;
10137 }
10138 if (extra.loc) {
10139 token.loc = entry.loc;
10140 }
10141 tokens.push(token);
10142 }
10143
10144 extra.tokens = tokens;
10145 }
10146
10147 function tokenize(code, options, delegate) {
10148 var toString,
10149 tokens;
10150
10151 toString = String;
10152 if (typeof code !== 'string' && !(code instanceof String)) {
10153 code = toString(code);
10154 }
10155
10156 source = code;
10157 index = 0;
10158 lineNumber = (source.length > 0) ? 1 : 0;
10159 lineStart = 0;
10160 startIndex = index;
10161 startLineNumber = lineNumber;
10162 startLineStart = lineStart;
10163 length = source.length;
10164 lookahead = null;
10165 state = {
10166 allowIn: true,
10167 allowYield: true,
10168 labelSet: {},
10169 inFunctionBody: false,
10170 inIteration: false,
10171 inSwitch: false,
10172 lastCommentStart: -1,
10173 curlyStack: []
10174 };
10175
10176 extra = {};
10177
10178 // Options matching.
10179 options = options || {};
10180
10181 // Of course we collect tokens here.
10182 options.tokens = true;
10183 extra.tokens = [];
10184 extra.tokenValues = [];
10185 extra.tokenize = true;
10186 extra.delegate = delegate;
10187
10188 // The following two fields are necessary to compute the Regex tokens.
10189 extra.openParenToken = -1;
10190 extra.openCurlyToken = -1;
10191
10192 extra.range = (typeof options.range === 'boolean') && options.range;
10193 extra.loc = (typeof options.loc === 'boolean') && options.loc;
10194
10195 if (typeof options.comment === 'boolean' && options.comment) {
10196 extra.comments = [];
10197 }
10198 if (typeof options.tolerant === 'boolean' && options.tolerant) {
10199 extra.errors = [];
10200 }
10201
10202 try {
10203 peek();
10204 if (lookahead.type === Token.EOF) {
10205 return extra.tokens;
10206 }
10207
10208 lex();
10209 while (lookahead.type !== Token.EOF) {
10210 try {
10211 lex();
10212 } catch (lexError) {
10213 if (extra.errors) {
10214 recordError(lexError);
10215 // We have to break on the first error
10216 // to avoid infinite loops.
10217 break;
10218 } else {
10219 throw lexError;
10220 }
10221 }
10222 }
10223
10224 tokens = extra.tokens;
10225 if (typeof extra.errors !== 'undefined') {
10226 tokens.errors = extra.errors;
10227 }
10228 } catch (e) {
10229 throw e;
10230 } finally {
10231 extra = {};
10232 }
10233 return tokens;
10234 }
10235
10236 function parse(code, options) {
10237 var program, toString;
10238
10239 toString = String;
10240 if (typeof code !== 'string' && !(code instanceof String)) {
10241 code = toString(code);
10242 }
10243
10244 source = code;
10245 index = 0;
10246 lineNumber = (source.length > 0) ? 1 : 0;
10247 lineStart = 0;
10248 startIndex = index;
10249 startLineNumber = lineNumber;
10250 startLineStart = lineStart;
10251 length = source.length;
10252 lookahead = null;
10253 state = {
10254 allowIn: true,
10255 allowYield: true,
10256 labelSet: {},
10257 inFunctionBody: false,
10258 inIteration: false,
10259 inSwitch: false,
10260 lastCommentStart: -1,
10261 curlyStack: [],
10262 sourceType: 'script'
10263 };
10264 strict = false;
10265
10266 extra = {};
10267 if (typeof options !== 'undefined') {
10268 extra.range = (typeof options.range === 'boolean') && options.range;
10269 extra.loc = (typeof options.loc === 'boolean') && options.loc;
10270 extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
10271
10272 if (extra.loc && options.source !== null && options.source !== undefined) {
10273 extra.source = toString(options.source);
10274 }
10275
10276 if (typeof options.tokens === 'boolean' && options.tokens) {
10277 extra.tokens = [];
10278 }
10279 if (typeof options.comment === 'boolean' && options.comment) {
10280 extra.comments = [];
10281 }
10282 if (typeof options.tolerant === 'boolean' && options.tolerant) {
10283 extra.errors = [];
10284 }
10285 if (extra.attachComment) {
10286 extra.range = true;
10287 extra.comments = [];
10288 extra.bottomRightStack = [];
10289 extra.trailingComments = [];
10290 extra.leadingComments = [];
10291 }
10292 if (options.sourceType === 'module') {
10293 // very restrictive condition for now
10294 state.sourceType = options.sourceType;
10295 strict = true;
10296 }
10297 }
10298
10299 try {
10300 program = parseProgram();
10301 if (typeof extra.comments !== 'undefined') {
10302 program.comments = extra.comments;
10303 }
10304 if (typeof extra.tokens !== 'undefined') {
10305 filterTokenLocation();
10306 program.tokens = extra.tokens;
10307 }
10308 if (typeof extra.errors !== 'undefined') {
10309 program.errors = extra.errors;
10310 }
10311 } catch (e) {
10312 throw e;
10313 } finally {
10314 extra = {};
10315 }
10316
10317 return program;
10318 }
10319
10320 // Sync with *.json manifests.
10321 exports.version = '2.7.0';
10322
10323 exports.tokenize = tokenize;
10324
10325 exports.parse = parse;
10326
10327 // Deep copy.
10328 /* istanbul ignore next */
10329 exports.Syntax = (function () {
10330 var name, types = {};
10331
10332 if (typeof Object.create === 'function') {
10333 types = Object.create(null);
10334 }
10335
10336 for (name in Syntax) {
10337 if (Syntax.hasOwnProperty(name)) {
10338 types[name] = Syntax[name];
10339 }
10340 }
10341
10342 if (typeof Object.freeze === 'function') {
10343 Object.freeze(types);
10344 }
10345
10346 return types;
10347 }());
10348
10349}));
10350/* vim: set sw=4 ts=4 et tw=80 : */
10351/**
10352 * @license Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
10353 * Available via the MIT or new BSD license.
10354 * see: http://github.com/jrburke/requirejs for details
10355 */
10356
10357/*global define, Reflect */
10358
10359/*
10360 * xpcshell has a smaller stack on linux and windows (1MB vs 9MB on mac),
10361 * and the recursive nature of esprima can cause it to overflow pretty
10362 * quickly. So favor it built in Reflect parser:
10363 * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
10364 */
10365define('esprimaAdapter', ['./esprima', 'env'], function (esprima, env) {
10366 if (env.get() === 'xpconnect' && typeof Reflect !== 'undefined') {
10367 return Reflect;
10368 } else {
10369 return esprima;
10370 }
10371});
10372(function webpackUniversalModuleDefinition(root, factory) {
10373var exports, module;
10374 if(typeof exports === 'object' && typeof module === 'object')
10375 module.exports = factory();
10376 else if(typeof define === 'function' && define.amd)
10377 define('source-map', [], factory);
10378 else if(typeof exports === 'object')
10379 exports["sourceMap"] = factory();
10380 else
10381 root["sourceMap"] = factory();
10382})(this, function() {
10383return /******/ (function(modules) { // webpackBootstrap
10384/******/ // The module cache
10385/******/ var installedModules = {};
10386
10387/******/ // The require function
10388/******/ function __webpack_require__(moduleId) {
10389
10390/******/ // Check if module is in cache
10391/******/ if(installedModules[moduleId])
10392/******/ return installedModules[moduleId].exports;
10393
10394/******/ // Create a new module (and put it into the cache)
10395/******/ var module = installedModules[moduleId] = {
10396/******/ exports: {},
10397/******/ id: moduleId,
10398/******/ loaded: false
10399/******/ };
10400
10401/******/ // Execute the module function
10402/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
10403
10404/******/ // Flag the module as loaded
10405/******/ module.loaded = true;
10406
10407/******/ // Return the exports of the module
10408/******/ return module.exports;
10409/******/ }
10410
10411
10412/******/ // expose the modules object (__webpack_modules__)
10413/******/ __webpack_require__.m = modules;
10414
10415/******/ // expose the module cache
10416/******/ __webpack_require__.c = installedModules;
10417
10418/******/ // __webpack_public_path__
10419/******/ __webpack_require__.p = "";
10420
10421/******/ // Load entry module and return exports
10422/******/ return __webpack_require__(0);
10423/******/ })
10424/************************************************************************/
10425/******/ ([
10426/* 0 */
10427/***/ function(module, exports, __webpack_require__) {
10428
10429 /*
10430 * Copyright 2009-2011 Mozilla Foundation and contributors
10431 * Licensed under the New BSD license. See LICENSE.txt or:
10432 * http://opensource.org/licenses/BSD-3-Clause
10433 */
10434 exports.SourceMapGenerator = __webpack_require__(1).SourceMapGenerator;
10435 exports.SourceMapConsumer = __webpack_require__(7).SourceMapConsumer;
10436 exports.SourceNode = __webpack_require__(10).SourceNode;
10437
10438
10439/***/ },
10440/* 1 */
10441/***/ function(module, exports, __webpack_require__) {
10442
10443 /* -*- Mode: js; js-indent-level: 2; -*- */
10444 /*
10445 * Copyright 2011 Mozilla Foundation and contributors
10446 * Licensed under the New BSD license. See LICENSE or:
10447 * http://opensource.org/licenses/BSD-3-Clause
10448 */
10449 {
10450 var base64VLQ = __webpack_require__(2);
10451 var util = __webpack_require__(4);
10452 var ArraySet = __webpack_require__(5).ArraySet;
10453 var MappingList = __webpack_require__(6).MappingList;
10454
10455 /**
10456 * An instance of the SourceMapGenerator represents a source map which is
10457 * being built incrementally. You may pass an object with the following
10458 * properties:
10459 *
10460 * - file: The filename of the generated source.
10461 * - sourceRoot: A root for all relative URLs in this source map.
10462 */
10463 function SourceMapGenerator(aArgs) {
10464 if (!aArgs) {
10465 aArgs = {};
10466 }
10467 this._file = util.getArg(aArgs, 'file', null);
10468 this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
10469 this._skipValidation = util.getArg(aArgs, 'skipValidation', false);
10470 this._sources = new ArraySet();
10471 this._names = new ArraySet();
10472 this._mappings = new MappingList();
10473 this._sourcesContents = null;
10474 }
10475
10476 SourceMapGenerator.prototype._version = 3;
10477
10478 /**
10479 * Creates a new SourceMapGenerator based on a SourceMapConsumer
10480 *
10481 * @param aSourceMapConsumer The SourceMap.
10482 */
10483 SourceMapGenerator.fromSourceMap =
10484 function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
10485 var sourceRoot = aSourceMapConsumer.sourceRoot;
10486 var generator = new SourceMapGenerator({
10487 file: aSourceMapConsumer.file,
10488 sourceRoot: sourceRoot
10489 });
10490 aSourceMapConsumer.eachMapping(function (mapping) {
10491 var newMapping = {
10492 generated: {
10493 line: mapping.generatedLine,
10494 column: mapping.generatedColumn
10495 }
10496 };
10497
10498 if (mapping.source != null) {
10499 newMapping.source = mapping.source;
10500 if (sourceRoot != null) {
10501 newMapping.source = util.relative(sourceRoot, newMapping.source);
10502 }
10503
10504 newMapping.original = {
10505 line: mapping.originalLine,
10506 column: mapping.originalColumn
10507 };
10508
10509 if (mapping.name != null) {
10510 newMapping.name = mapping.name;
10511 }
10512 }
10513
10514 generator.addMapping(newMapping);
10515 });
10516 aSourceMapConsumer.sources.forEach(function (sourceFile) {
10517 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
10518 if (content != null) {
10519 generator.setSourceContent(sourceFile, content);
10520 }
10521 });
10522 return generator;
10523 };
10524
10525 /**
10526 * Add a single mapping from original source line and column to the generated
10527 * source's line and column for this source map being created. The mapping
10528 * object should have the following properties:
10529 *
10530 * - generated: An object with the generated line and column positions.
10531 * - original: An object with the original line and column positions.
10532 * - source: The original source file (relative to the sourceRoot).
10533 * - name: An optional original token name for this mapping.
10534 */
10535 SourceMapGenerator.prototype.addMapping =
10536 function SourceMapGenerator_addMapping(aArgs) {
10537 var generated = util.getArg(aArgs, 'generated');
10538 var original = util.getArg(aArgs, 'original', null);
10539 var source = util.getArg(aArgs, 'source', null);
10540 var name = util.getArg(aArgs, 'name', null);
10541
10542 if (!this._skipValidation) {
10543 this._validateMapping(generated, original, source, name);
10544 }
10545
10546 if (source != null && !this._sources.has(source)) {
10547 this._sources.add(source);
10548 }
10549
10550 if (name != null && !this._names.has(name)) {
10551 this._names.add(name);
10552 }
10553
10554 this._mappings.add({
10555 generatedLine: generated.line,
10556 generatedColumn: generated.column,
10557 originalLine: original != null && original.line,
10558 originalColumn: original != null && original.column,
10559 source: source,
10560 name: name
10561 });
10562 };
10563
10564 /**
10565 * Set the source content for a source file.
10566 */
10567 SourceMapGenerator.prototype.setSourceContent =
10568 function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
10569 var source = aSourceFile;
10570 if (this._sourceRoot != null) {
10571 source = util.relative(this._sourceRoot, source);
10572 }
10573
10574 if (aSourceContent != null) {
10575 // Add the source content to the _sourcesContents map.
10576 // Create a new _sourcesContents map if the property is null.
10577 if (!this._sourcesContents) {
10578 this._sourcesContents = {};
10579 }
10580 this._sourcesContents[util.toSetString(source)] = aSourceContent;
10581 } else if (this._sourcesContents) {
10582 // Remove the source file from the _sourcesContents map.
10583 // If the _sourcesContents map is empty, set the property to null.
10584 delete this._sourcesContents[util.toSetString(source)];
10585 if (Object.keys(this._sourcesContents).length === 0) {
10586 this._sourcesContents = null;
10587 }
10588 }
10589 };
10590
10591 /**
10592 * Applies the mappings of a sub-source-map for a specific source file to the
10593 * source map being generated. Each mapping to the supplied source file is
10594 * rewritten using the supplied source map. Note: The resolution for the
10595 * resulting mappings is the minimium of this map and the supplied map.
10596 *
10597 * @param aSourceMapConsumer The source map to be applied.
10598 * @param aSourceFile Optional. The filename of the source file.
10599 * If omitted, SourceMapConsumer's file property will be used.
10600 * @param aSourceMapPath Optional. The dirname of the path to the source map
10601 * to be applied. If relative, it is relative to the SourceMapConsumer.
10602 * This parameter is needed when the two source maps aren't in the same
10603 * directory, and the source map to be applied contains relative source
10604 * paths. If so, those relative source paths need to be rewritten
10605 * relative to the SourceMapGenerator.
10606 */
10607 SourceMapGenerator.prototype.applySourceMap =
10608 function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
10609 var sourceFile = aSourceFile;
10610 // If aSourceFile is omitted, we will use the file property of the SourceMap
10611 if (aSourceFile == null) {
10612 if (aSourceMapConsumer.file == null) {
10613 throw new Error(
10614 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' +
10615 'or the source map\'s "file" property. Both were omitted.'
10616 );
10617 }
10618 sourceFile = aSourceMapConsumer.file;
10619 }
10620 var sourceRoot = this._sourceRoot;
10621 // Make "sourceFile" relative if an absolute Url is passed.
10622 if (sourceRoot != null) {
10623 sourceFile = util.relative(sourceRoot, sourceFile);
10624 }
10625 // Applying the SourceMap can add and remove items from the sources and
10626 // the names array.
10627 var newSources = new ArraySet();
10628 var newNames = new ArraySet();
10629
10630 // Find mappings for the "sourceFile"
10631 this._mappings.unsortedForEach(function (mapping) {
10632 if (mapping.source === sourceFile && mapping.originalLine != null) {
10633 // Check if it can be mapped by the source map, then update the mapping.
10634 var original = aSourceMapConsumer.originalPositionFor({
10635 line: mapping.originalLine,
10636 column: mapping.originalColumn
10637 });
10638 if (original.source != null) {
10639 // Copy mapping
10640 mapping.source = original.source;
10641 if (aSourceMapPath != null) {
10642 mapping.source = util.join(aSourceMapPath, mapping.source)
10643 }
10644 if (sourceRoot != null) {
10645 mapping.source = util.relative(sourceRoot, mapping.source);
10646 }
10647 mapping.originalLine = original.line;
10648 mapping.originalColumn = original.column;
10649 if (original.name != null) {
10650 mapping.name = original.name;
10651 }
10652 }
10653 }
10654
10655 var source = mapping.source;
10656 if (source != null && !newSources.has(source)) {
10657 newSources.add(source);
10658 }
10659
10660 var name = mapping.name;
10661 if (name != null && !newNames.has(name)) {
10662 newNames.add(name);
10663 }
10664
10665 }, this);
10666 this._sources = newSources;
10667 this._names = newNames;
10668
10669 // Copy sourcesContents of applied map.
10670 aSourceMapConsumer.sources.forEach(function (sourceFile) {
10671 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
10672 if (content != null) {
10673 if (aSourceMapPath != null) {
10674 sourceFile = util.join(aSourceMapPath, sourceFile);
10675 }
10676 if (sourceRoot != null) {
10677 sourceFile = util.relative(sourceRoot, sourceFile);
10678 }
10679 this.setSourceContent(sourceFile, content);
10680 }
10681 }, this);
10682 };
10683
10684 /**
10685 * A mapping can have one of the three levels of data:
10686 *
10687 * 1. Just the generated position.
10688 * 2. The Generated position, original position, and original source.
10689 * 3. Generated and original position, original source, as well as a name
10690 * token.
10691 *
10692 * To maintain consistency, we validate that any new mapping being added falls
10693 * in to one of these categories.
10694 */
10695 SourceMapGenerator.prototype._validateMapping =
10696 function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
10697 aName) {
10698 if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
10699 && aGenerated.line > 0 && aGenerated.column >= 0
10700 && !aOriginal && !aSource && !aName) {
10701 // Case 1.
10702 return;
10703 }
10704 else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
10705 && aOriginal && 'line' in aOriginal && 'column' in aOriginal
10706 && aGenerated.line > 0 && aGenerated.column >= 0
10707 && aOriginal.line > 0 && aOriginal.column >= 0
10708 && aSource) {
10709 // Cases 2 and 3.
10710 return;
10711 }
10712 else {
10713 throw new Error('Invalid mapping: ' + JSON.stringify({
10714 generated: aGenerated,
10715 source: aSource,
10716 original: aOriginal,
10717 name: aName
10718 }));
10719 }
10720 };
10721
10722 /**
10723 * Serialize the accumulated mappings in to the stream of base 64 VLQs
10724 * specified by the source map format.
10725 */
10726 SourceMapGenerator.prototype._serializeMappings =
10727 function SourceMapGenerator_serializeMappings() {
10728 var previousGeneratedColumn = 0;
10729 var previousGeneratedLine = 1;
10730 var previousOriginalColumn = 0;
10731 var previousOriginalLine = 0;
10732 var previousName = 0;
10733 var previousSource = 0;
10734 var result = '';
10735 var mapping;
10736 var nameIdx;
10737 var sourceIdx;
10738
10739 var mappings = this._mappings.toArray();
10740 for (var i = 0, len = mappings.length; i < len; i++) {
10741 mapping = mappings[i];
10742
10743 if (mapping.generatedLine !== previousGeneratedLine) {
10744 previousGeneratedColumn = 0;
10745 while (mapping.generatedLine !== previousGeneratedLine) {
10746 result += ';';
10747 previousGeneratedLine++;
10748 }
10749 }
10750 else {
10751 if (i > 0) {
10752 if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) {
10753 continue;
10754 }
10755 result += ',';
10756 }
10757 }
10758
10759 result += base64VLQ.encode(mapping.generatedColumn
10760 - previousGeneratedColumn);
10761 previousGeneratedColumn = mapping.generatedColumn;
10762
10763 if (mapping.source != null) {
10764 sourceIdx = this._sources.indexOf(mapping.source);
10765 result += base64VLQ.encode(sourceIdx - previousSource);
10766 previousSource = sourceIdx;
10767
10768 // lines are stored 0-based in SourceMap spec version 3
10769 result += base64VLQ.encode(mapping.originalLine - 1
10770 - previousOriginalLine);
10771 previousOriginalLine = mapping.originalLine - 1;
10772
10773 result += base64VLQ.encode(mapping.originalColumn
10774 - previousOriginalColumn);
10775 previousOriginalColumn = mapping.originalColumn;
10776
10777 if (mapping.name != null) {
10778 nameIdx = this._names.indexOf(mapping.name);
10779 result += base64VLQ.encode(nameIdx - previousName);
10780 previousName = nameIdx;
10781 }
10782 }
10783 }
10784
10785 return result;
10786 };
10787
10788 SourceMapGenerator.prototype._generateSourcesContent =
10789 function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
10790 return aSources.map(function (source) {
10791 if (!this._sourcesContents) {
10792 return null;
10793 }
10794 if (aSourceRoot != null) {
10795 source = util.relative(aSourceRoot, source);
10796 }
10797 var key = util.toSetString(source);
10798 return Object.prototype.hasOwnProperty.call(this._sourcesContents,
10799 key)
10800 ? this._sourcesContents[key]
10801 : null;
10802 }, this);
10803 };
10804
10805 /**
10806 * Externalize the source map.
10807 */
10808 SourceMapGenerator.prototype.toJSON =
10809 function SourceMapGenerator_toJSON() {
10810 var map = {
10811 version: this._version,
10812 sources: this._sources.toArray(),
10813 names: this._names.toArray(),
10814 mappings: this._serializeMappings()
10815 };
10816 if (this._file != null) {
10817 map.file = this._file;
10818 }
10819 if (this._sourceRoot != null) {
10820 map.sourceRoot = this._sourceRoot;
10821 }
10822 if (this._sourcesContents) {
10823 map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
10824 }
10825
10826 return map;
10827 };
10828
10829 /**
10830 * Render the source map being generated to a string.
10831 */
10832 SourceMapGenerator.prototype.toString =
10833 function SourceMapGenerator_toString() {
10834 return JSON.stringify(this.toJSON());
10835 };
10836
10837 exports.SourceMapGenerator = SourceMapGenerator;
10838 }
10839
10840
10841/***/ },
10842/* 2 */
10843/***/ function(module, exports, __webpack_require__) {
10844
10845 /* -*- Mode: js; js-indent-level: 2; -*- */
10846 /*
10847 * Copyright 2011 Mozilla Foundation and contributors
10848 * Licensed under the New BSD license. See LICENSE or:
10849 * http://opensource.org/licenses/BSD-3-Clause
10850 *
10851 * Based on the Base 64 VLQ implementation in Closure Compiler:
10852 * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java
10853 *
10854 * Copyright 2011 The Closure Compiler Authors. All rights reserved.
10855 * Redistribution and use in source and binary forms, with or without
10856 * modification, are permitted provided that the following conditions are
10857 * met:
10858 *
10859 * * Redistributions of source code must retain the above copyright
10860 * notice, this list of conditions and the following disclaimer.
10861 * * Redistributions in binary form must reproduce the above
10862 * copyright notice, this list of conditions and the following
10863 * disclaimer in the documentation and/or other materials provided
10864 * with the distribution.
10865 * * Neither the name of Google Inc. nor the names of its
10866 * contributors may be used to endorse or promote products derived
10867 * from this software without specific prior written permission.
10868 *
10869 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10870 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10871 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
10872 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
10873 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10874 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10875 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10876 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
10877 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10878 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
10879 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10880 */
10881 {
10882 var base64 = __webpack_require__(3);
10883
10884 // A single base 64 digit can contain 6 bits of data. For the base 64 variable
10885 // length quantities we use in the source map spec, the first bit is the sign,
10886 // the next four bits are the actual value, and the 6th bit is the
10887 // continuation bit. The continuation bit tells us whether there are more
10888 // digits in this value following this digit.
10889 //
10890 // Continuation
10891 // | Sign
10892 // | |
10893 // V V
10894 // 101011
10895
10896 var VLQ_BASE_SHIFT = 5;
10897
10898 // binary: 100000
10899 var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
10900
10901 // binary: 011111
10902 var VLQ_BASE_MASK = VLQ_BASE - 1;
10903
10904 // binary: 100000
10905 var VLQ_CONTINUATION_BIT = VLQ_BASE;
10906
10907 /**
10908 * Converts from a two-complement value to a value where the sign bit is
10909 * placed in the least significant bit. For example, as decimals:
10910 * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
10911 * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
10912 */
10913 function toVLQSigned(aValue) {
10914 return aValue < 0
10915 ? ((-aValue) << 1) + 1
10916 : (aValue << 1) + 0;
10917 }
10918
10919 /**
10920 * Converts to a two-complement value from a value where the sign bit is
10921 * placed in the least significant bit. For example, as decimals:
10922 * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
10923 * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
10924 */
10925 function fromVLQSigned(aValue) {
10926 var isNegative = (aValue & 1) === 1;
10927 var shifted = aValue >> 1;
10928 return isNegative
10929 ? -shifted
10930 : shifted;
10931 }
10932
10933 /**
10934 * Returns the base 64 VLQ encoded value.
10935 */
10936 exports.encode = function base64VLQ_encode(aValue) {
10937 var encoded = "";
10938 var digit;
10939
10940 var vlq = toVLQSigned(aValue);
10941
10942 do {
10943 digit = vlq & VLQ_BASE_MASK;
10944 vlq >>>= VLQ_BASE_SHIFT;
10945 if (vlq > 0) {
10946 // There are still more digits in this value, so we must make sure the
10947 // continuation bit is marked.
10948 digit |= VLQ_CONTINUATION_BIT;
10949 }
10950 encoded += base64.encode(digit);
10951 } while (vlq > 0);
10952
10953 return encoded;
10954 };
10955
10956 /**
10957 * Decodes the next base 64 VLQ value from the given string and returns the
10958 * value and the rest of the string via the out parameter.
10959 */
10960 exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) {
10961 var strLen = aStr.length;
10962 var result = 0;
10963 var shift = 0;
10964 var continuation, digit;
10965
10966 do {
10967 if (aIndex >= strLen) {
10968 throw new Error("Expected more digits in base 64 VLQ value.");
10969 }
10970
10971 digit = base64.decode(aStr.charCodeAt(aIndex++));
10972 if (digit === -1) {
10973 throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1));
10974 }
10975
10976 continuation = !!(digit & VLQ_CONTINUATION_BIT);
10977 digit &= VLQ_BASE_MASK;
10978 result = result + (digit << shift);
10979 shift += VLQ_BASE_SHIFT;
10980 } while (continuation);
10981
10982 aOutParam.value = fromVLQSigned(result);
10983 aOutParam.rest = aIndex;
10984 };
10985 }
10986
10987
10988/***/ },
10989/* 3 */
10990/***/ function(module, exports) {
10991
10992 /* -*- Mode: js; js-indent-level: 2; -*- */
10993 /*
10994 * Copyright 2011 Mozilla Foundation and contributors
10995 * Licensed under the New BSD license. See LICENSE or:
10996 * http://opensource.org/licenses/BSD-3-Clause
10997 */
10998 {
10999 var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
11000
11001 /**
11002 * Encode an integer in the range of 0 to 63 to a single base 64 digit.
11003 */
11004 exports.encode = function (number) {
11005 if (0 <= number && number < intToCharMap.length) {
11006 return intToCharMap[number];
11007 }
11008 throw new TypeError("Must be between 0 and 63: " + number);
11009 };
11010
11011 /**
11012 * Decode a single base 64 character code digit to an integer. Returns -1 on
11013 * failure.
11014 */
11015 exports.decode = function (charCode) {
11016 var bigA = 65; // 'A'
11017 var bigZ = 90; // 'Z'
11018
11019 var littleA = 97; // 'a'
11020 var littleZ = 122; // 'z'
11021
11022 var zero = 48; // '0'
11023 var nine = 57; // '9'
11024
11025 var plus = 43; // '+'
11026 var slash = 47; // '/'
11027
11028 var littleOffset = 26;
11029 var numberOffset = 52;
11030
11031 // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ
11032 if (bigA <= charCode && charCode <= bigZ) {
11033 return (charCode - bigA);
11034 }
11035
11036 // 26 - 51: abcdefghijklmnopqrstuvwxyz
11037 if (littleA <= charCode && charCode <= littleZ) {
11038 return (charCode - littleA + littleOffset);
11039 }
11040
11041 // 52 - 61: 0123456789
11042 if (zero <= charCode && charCode <= nine) {
11043 return (charCode - zero + numberOffset);
11044 }
11045
11046 // 62: +
11047 if (charCode == plus) {
11048 return 62;
11049 }
11050
11051 // 63: /
11052 if (charCode == slash) {
11053 return 63;
11054 }
11055
11056 // Invalid base64 digit.
11057 return -1;
11058 };
11059 }
11060
11061
11062/***/ },
11063/* 4 */
11064/***/ function(module, exports) {
11065
11066 /* -*- Mode: js; js-indent-level: 2; -*- */
11067 /*
11068 * Copyright 2011 Mozilla Foundation and contributors
11069 * Licensed under the New BSD license. See LICENSE or:
11070 * http://opensource.org/licenses/BSD-3-Clause
11071 */
11072 {
11073 /**
11074 * This is a helper function for getting values from parameter/options
11075 * objects.
11076 *
11077 * @param args The object we are extracting values from
11078 * @param name The name of the property we are getting.
11079 * @param defaultValue An optional value to return if the property is missing
11080 * from the object. If this is not specified and the property is missing, an
11081 * error will be thrown.
11082 */
11083 function getArg(aArgs, aName, aDefaultValue) {
11084 if (aName in aArgs) {
11085 return aArgs[aName];
11086 } else if (arguments.length === 3) {
11087 return aDefaultValue;
11088 } else {
11089 throw new Error('"' + aName + '" is a required argument.');
11090 }
11091 }
11092 exports.getArg = getArg;
11093
11094 var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/;
11095 var dataUrlRegexp = /^data:.+\,.+$/;
11096
11097 function urlParse(aUrl) {
11098 var match = aUrl.match(urlRegexp);
11099 if (!match) {
11100 return null;
11101 }
11102 return {
11103 scheme: match[1],
11104 auth: match[2],
11105 host: match[3],
11106 port: match[4],
11107 path: match[5]
11108 };
11109 }
11110 exports.urlParse = urlParse;
11111
11112 function urlGenerate(aParsedUrl) {
11113 var url = '';
11114 if (aParsedUrl.scheme) {
11115 url += aParsedUrl.scheme + ':';
11116 }
11117 url += '//';
11118 if (aParsedUrl.auth) {
11119 url += aParsedUrl.auth + '@';
11120 }
11121 if (aParsedUrl.host) {
11122 url += aParsedUrl.host;
11123 }
11124 if (aParsedUrl.port) {
11125 url += ":" + aParsedUrl.port
11126 }
11127 if (aParsedUrl.path) {
11128 url += aParsedUrl.path;
11129 }
11130 return url;
11131 }
11132 exports.urlGenerate = urlGenerate;
11133
11134 /**
11135 * Normalizes a path, or the path portion of a URL:
11136 *
11137 * - Replaces consequtive slashes with one slash.
11138 * - Removes unnecessary '.' parts.
11139 * - Removes unnecessary '<dir>/..' parts.
11140 *
11141 * Based on code in the Node.js 'path' core module.
11142 *
11143 * @param aPath The path or url to normalize.
11144 */
11145 function normalize(aPath) {
11146 var path = aPath;
11147 var url = urlParse(aPath);
11148 if (url) {
11149 if (!url.path) {
11150 return aPath;
11151 }
11152 path = url.path;
11153 }
11154 var isAbsolute = exports.isAbsolute(path);
11155
11156 var parts = path.split(/\/+/);
11157 for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
11158 part = parts[i];
11159 if (part === '.') {
11160 parts.splice(i, 1);
11161 } else if (part === '..') {
11162 up++;
11163 } else if (up > 0) {
11164 if (part === '') {
11165 // The first part is blank if the path is absolute. Trying to go
11166 // above the root is a no-op. Therefore we can remove all '..' parts
11167 // directly after the root.
11168 parts.splice(i + 1, up);
11169 up = 0;
11170 } else {
11171 parts.splice(i, 2);
11172 up--;
11173 }
11174 }
11175 }
11176 path = parts.join('/');
11177
11178 if (path === '') {
11179 path = isAbsolute ? '/' : '.';
11180 }
11181
11182 if (url) {
11183 url.path = path;
11184 return urlGenerate(url);
11185 }
11186 return path;
11187 }
11188 exports.normalize = normalize;
11189
11190 /**
11191 * Joins two paths/URLs.
11192 *
11193 * @param aRoot The root path or URL.
11194 * @param aPath The path or URL to be joined with the root.
11195 *
11196 * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a
11197 * scheme-relative URL: Then the scheme of aRoot, if any, is prepended
11198 * first.
11199 * - Otherwise aPath is a path. If aRoot is a URL, then its path portion
11200 * is updated with the result and aRoot is returned. Otherwise the result
11201 * is returned.
11202 * - If aPath is absolute, the result is aPath.
11203 * - Otherwise the two paths are joined with a slash.
11204 * - Joining for example 'http://' and 'www.example.com' is also supported.
11205 */
11206 function join(aRoot, aPath) {
11207 if (aRoot === "") {
11208 aRoot = ".";
11209 }
11210 if (aPath === "") {
11211 aPath = ".";
11212 }
11213 var aPathUrl = urlParse(aPath);
11214 var aRootUrl = urlParse(aRoot);
11215 if (aRootUrl) {
11216 aRoot = aRootUrl.path || '/';
11217 }
11218
11219 // `join(foo, '//www.example.org')`
11220 if (aPathUrl && !aPathUrl.scheme) {
11221 if (aRootUrl) {
11222 aPathUrl.scheme = aRootUrl.scheme;
11223 }
11224 return urlGenerate(aPathUrl);
11225 }
11226
11227 if (aPathUrl || aPath.match(dataUrlRegexp)) {
11228 return aPath;
11229 }
11230
11231 // `join('http://', 'www.example.com')`
11232 if (aRootUrl && !aRootUrl.host && !aRootUrl.path) {
11233 aRootUrl.host = aPath;
11234 return urlGenerate(aRootUrl);
11235 }
11236
11237 var joined = aPath.charAt(0) === '/'
11238 ? aPath
11239 : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath);
11240
11241 if (aRootUrl) {
11242 aRootUrl.path = joined;
11243 return urlGenerate(aRootUrl);
11244 }
11245 return joined;
11246 }
11247 exports.join = join;
11248
11249 exports.isAbsolute = function (aPath) {
11250 return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp);
11251 };
11252
11253 /**
11254 * Make a path relative to a URL or another path.
11255 *
11256 * @param aRoot The root path or URL.
11257 * @param aPath The path or URL to be made relative to aRoot.
11258 */
11259 function relative(aRoot, aPath) {
11260 if (aRoot === "") {
11261 aRoot = ".";
11262 }
11263
11264 aRoot = aRoot.replace(/\/$/, '');
11265
11266 // It is possible for the path to be above the root. In this case, simply
11267 // checking whether the root is a prefix of the path won't work. Instead, we
11268 // need to remove components from the root one by one, until either we find
11269 // a prefix that fits, or we run out of components to remove.
11270 var level = 0;
11271 while (aPath.indexOf(aRoot + '/') !== 0) {
11272 var index = aRoot.lastIndexOf("/");
11273 if (index < 0) {
11274 return aPath;
11275 }
11276
11277 // If the only part of the root that is left is the scheme (i.e. http://,
11278 // file:///, etc.), one or more slashes (/), or simply nothing at all, we
11279 // have exhausted all components, so the path is not relative to the root.
11280 aRoot = aRoot.slice(0, index);
11281 if (aRoot.match(/^([^\/]+:\/)?\/*$/)) {
11282 return aPath;
11283 }
11284
11285 ++level;
11286 }
11287
11288 // Make sure we add a "../" for each component we removed from the root.
11289 return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
11290 }
11291 exports.relative = relative;
11292
11293 /**
11294 * Because behavior goes wacky when you set `__proto__` on objects, we
11295 * have to prefix all the strings in our set with an arbitrary character.
11296 *
11297 * See https://github.com/mozilla/source-map/pull/31 and
11298 * https://github.com/mozilla/source-map/issues/30
11299 *
11300 * @param String aStr
11301 */
11302 function toSetString(aStr) {
11303 return '$' + aStr;
11304 }
11305 exports.toSetString = toSetString;
11306
11307 function fromSetString(aStr) {
11308 return aStr.substr(1);
11309 }
11310 exports.fromSetString = fromSetString;
11311
11312 /**
11313 * Comparator between two mappings where the original positions are compared.
11314 *
11315 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
11316 * mappings with the same original source/line/column, but different generated
11317 * line and column the same. Useful when searching for a mapping with a
11318 * stubbed out mapping.
11319 */
11320 function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) {
11321 var cmp = mappingA.source - mappingB.source;
11322 if (cmp !== 0) {
11323 return cmp;
11324 }
11325
11326 cmp = mappingA.originalLine - mappingB.originalLine;
11327 if (cmp !== 0) {
11328 return cmp;
11329 }
11330
11331 cmp = mappingA.originalColumn - mappingB.originalColumn;
11332 if (cmp !== 0 || onlyCompareOriginal) {
11333 return cmp;
11334 }
11335
11336 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
11337 if (cmp !== 0) {
11338 return cmp;
11339 }
11340
11341 cmp = mappingA.generatedLine - mappingB.generatedLine;
11342 if (cmp !== 0) {
11343 return cmp;
11344 }
11345
11346 return mappingA.name - mappingB.name;
11347 }
11348 exports.compareByOriginalPositions = compareByOriginalPositions;
11349
11350 /**
11351 * Comparator between two mappings with deflated source and name indices where
11352 * the generated positions are compared.
11353 *
11354 * Optionally pass in `true` as `onlyCompareGenerated` to consider two
11355 * mappings with the same generated line and column, but different
11356 * source/name/original line and column the same. Useful when searching for a
11357 * mapping with a stubbed out mapping.
11358 */
11359 function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) {
11360 var cmp = mappingA.generatedLine - mappingB.generatedLine;
11361 if (cmp !== 0) {
11362 return cmp;
11363 }
11364
11365 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
11366 if (cmp !== 0 || onlyCompareGenerated) {
11367 return cmp;
11368 }
11369
11370 cmp = mappingA.source - mappingB.source;
11371 if (cmp !== 0) {
11372 return cmp;
11373 }
11374
11375 cmp = mappingA.originalLine - mappingB.originalLine;
11376 if (cmp !== 0) {
11377 return cmp;
11378 }
11379
11380 cmp = mappingA.originalColumn - mappingB.originalColumn;
11381 if (cmp !== 0) {
11382 return cmp;
11383 }
11384
11385 return mappingA.name - mappingB.name;
11386 }
11387 exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated;
11388
11389 function strcmp(aStr1, aStr2) {
11390 if (aStr1 === aStr2) {
11391 return 0;
11392 }
11393
11394 if (aStr1 > aStr2) {
11395 return 1;
11396 }
11397
11398 return -1;
11399 }
11400
11401 /**
11402 * Comparator between two mappings with inflated source and name strings where
11403 * the generated positions are compared.
11404 */
11405 function compareByGeneratedPositionsInflated(mappingA, mappingB) {
11406 var cmp = mappingA.generatedLine - mappingB.generatedLine;
11407 if (cmp !== 0) {
11408 return cmp;
11409 }
11410
11411 cmp = mappingA.generatedColumn - mappingB.generatedColumn;
11412 if (cmp !== 0) {
11413 return cmp;
11414 }
11415
11416 cmp = strcmp(mappingA.source, mappingB.source);
11417 if (cmp !== 0) {
11418 return cmp;
11419 }
11420
11421 cmp = mappingA.originalLine - mappingB.originalLine;
11422 if (cmp !== 0) {
11423 return cmp;
11424 }
11425
11426 cmp = mappingA.originalColumn - mappingB.originalColumn;
11427 if (cmp !== 0) {
11428 return cmp;
11429 }
11430
11431 return strcmp(mappingA.name, mappingB.name);
11432 }
11433 exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated;
11434 }
11435
11436
11437/***/ },
11438/* 5 */
11439/***/ function(module, exports, __webpack_require__) {
11440
11441 /* -*- Mode: js; js-indent-level: 2; -*- */
11442 /*
11443 * Copyright 2011 Mozilla Foundation and contributors
11444 * Licensed under the New BSD license. See LICENSE or:
11445 * http://opensource.org/licenses/BSD-3-Clause
11446 */
11447 {
11448 var util = __webpack_require__(4);
11449
11450 /**
11451 * A data structure which is a combination of an array and a set. Adding a new
11452 * member is O(1), testing for membership is O(1), and finding the index of an
11453 * element is O(1). Removing elements from the set is not supported. Only
11454 * strings are supported for membership.
11455 */
11456 function ArraySet() {
11457 this._array = [];
11458 this._set = {};
11459 }
11460
11461 /**
11462 * Static method for creating ArraySet instances from an existing array.
11463 */
11464 ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) {
11465 var set = new ArraySet();
11466 for (var i = 0, len = aArray.length; i < len; i++) {
11467 set.add(aArray[i], aAllowDuplicates);
11468 }
11469 return set;
11470 };
11471
11472 /**
11473 * Return how many unique items are in this ArraySet. If duplicates have been
11474 * added, than those do not count towards the size.
11475 *
11476 * @returns Number
11477 */
11478 ArraySet.prototype.size = function ArraySet_size() {
11479 return Object.getOwnPropertyNames(this._set).length;
11480 };
11481
11482 /**
11483 * Add the given string to this set.
11484 *
11485 * @param String aStr
11486 */
11487 ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) {
11488 var sStr = util.toSetString(aStr);
11489 var isDuplicate = this._set.hasOwnProperty(sStr);
11490 var idx = this._array.length;
11491 if (!isDuplicate || aAllowDuplicates) {
11492 this._array.push(aStr);
11493 }
11494 if (!isDuplicate) {
11495 this._set[sStr] = idx;
11496 }
11497 };
11498
11499 /**
11500 * Is the given string a member of this set?
11501 *
11502 * @param String aStr
11503 */
11504 ArraySet.prototype.has = function ArraySet_has(aStr) {
11505 var sStr = util.toSetString(aStr);
11506 return this._set.hasOwnProperty(sStr);
11507 };
11508
11509 /**
11510 * What is the index of the given string in the array?
11511 *
11512 * @param String aStr
11513 */
11514 ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) {
11515 var sStr = util.toSetString(aStr);
11516 if (this._set.hasOwnProperty(sStr)) {
11517 return this._set[sStr];
11518 }
11519 throw new Error('"' + aStr + '" is not in the set.');
11520 };
11521
11522 /**
11523 * What is the element at the given index?
11524 *
11525 * @param Number aIdx
11526 */
11527 ArraySet.prototype.at = function ArraySet_at(aIdx) {
11528 if (aIdx >= 0 && aIdx < this._array.length) {
11529 return this._array[aIdx];
11530 }
11531 throw new Error('No element indexed by ' + aIdx);
11532 };
11533
11534 /**
11535 * Returns the array representation of this set (which has the proper indices
11536 * indicated by indexOf). Note that this is a copy of the internal array used
11537 * for storing the members so that no one can mess with internal state.
11538 */
11539 ArraySet.prototype.toArray = function ArraySet_toArray() {
11540 return this._array.slice();
11541 };
11542
11543 exports.ArraySet = ArraySet;
11544 }
11545
11546
11547/***/ },
11548/* 6 */
11549/***/ function(module, exports, __webpack_require__) {
11550
11551 /* -*- Mode: js; js-indent-level: 2; -*- */
11552 /*
11553 * Copyright 2014 Mozilla Foundation and contributors
11554 * Licensed under the New BSD license. See LICENSE or:
11555 * http://opensource.org/licenses/BSD-3-Clause
11556 */
11557 {
11558 var util = __webpack_require__(4);
11559
11560 /**
11561 * Determine whether mappingB is after mappingA with respect to generated
11562 * position.
11563 */
11564 function generatedPositionAfter(mappingA, mappingB) {
11565 // Optimized for most common case
11566 var lineA = mappingA.generatedLine;
11567 var lineB = mappingB.generatedLine;
11568 var columnA = mappingA.generatedColumn;
11569 var columnB = mappingB.generatedColumn;
11570 return lineB > lineA || lineB == lineA && columnB >= columnA ||
11571 util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0;
11572 }
11573
11574 /**
11575 * A data structure to provide a sorted view of accumulated mappings in a
11576 * performance conscious manner. It trades a neglibable overhead in general
11577 * case for a large speedup in case of mappings being added in order.
11578 */
11579 function MappingList() {
11580 this._array = [];
11581 this._sorted = true;
11582 // Serves as infimum
11583 this._last = {generatedLine: -1, generatedColumn: 0};
11584 }
11585
11586 /**
11587 * Iterate through internal items. This method takes the same arguments that
11588 * `Array.prototype.forEach` takes.
11589 *
11590 * NOTE: The order of the mappings is NOT guaranteed.
11591 */
11592 MappingList.prototype.unsortedForEach =
11593 function MappingList_forEach(aCallback, aThisArg) {
11594 this._array.forEach(aCallback, aThisArg);
11595 };
11596
11597 /**
11598 * Add the given source mapping.
11599 *
11600 * @param Object aMapping
11601 */
11602 MappingList.prototype.add = function MappingList_add(aMapping) {
11603 if (generatedPositionAfter(this._last, aMapping)) {
11604 this._last = aMapping;
11605 this._array.push(aMapping);
11606 } else {
11607 this._sorted = false;
11608 this._array.push(aMapping);
11609 }
11610 };
11611
11612 /**
11613 * Returns the flat, sorted array of mappings. The mappings are sorted by
11614 * generated position.
11615 *
11616 * WARNING: This method returns internal data without copying, for
11617 * performance. The return value must NOT be mutated, and should be treated as
11618 * an immutable borrow. If you want to take ownership, you must make your own
11619 * copy.
11620 */
11621 MappingList.prototype.toArray = function MappingList_toArray() {
11622 if (!this._sorted) {
11623 this._array.sort(util.compareByGeneratedPositionsInflated);
11624 this._sorted = true;
11625 }
11626 return this._array;
11627 };
11628
11629 exports.MappingList = MappingList;
11630 }
11631
11632
11633/***/ },
11634/* 7 */
11635/***/ function(module, exports, __webpack_require__) {
11636
11637 /* -*- Mode: js; js-indent-level: 2; -*- */
11638 /*
11639 * Copyright 2011 Mozilla Foundation and contributors
11640 * Licensed under the New BSD license. See LICENSE or:
11641 * http://opensource.org/licenses/BSD-3-Clause
11642 */
11643 {
11644 var util = __webpack_require__(4);
11645 var binarySearch = __webpack_require__(8);
11646 var ArraySet = __webpack_require__(5).ArraySet;
11647 var base64VLQ = __webpack_require__(2);
11648 var quickSort = __webpack_require__(9).quickSort;
11649
11650 function SourceMapConsumer(aSourceMap) {
11651 var sourceMap = aSourceMap;
11652 if (typeof aSourceMap === 'string') {
11653 sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
11654 }
11655
11656 return sourceMap.sections != null
11657 ? new IndexedSourceMapConsumer(sourceMap)
11658 : new BasicSourceMapConsumer(sourceMap);
11659 }
11660
11661 SourceMapConsumer.fromSourceMap = function(aSourceMap) {
11662 return BasicSourceMapConsumer.fromSourceMap(aSourceMap);
11663 }
11664
11665 /**
11666 * The version of the source mapping spec that we are consuming.
11667 */
11668 SourceMapConsumer.prototype._version = 3;
11669
11670 // `__generatedMappings` and `__originalMappings` are arrays that hold the
11671 // parsed mapping coordinates from the source map's "mappings" attribute. They
11672 // are lazily instantiated, accessed via the `_generatedMappings` and
11673 // `_originalMappings` getters respectively, and we only parse the mappings
11674 // and create these arrays once queried for a source location. We jump through
11675 // these hoops because there can be many thousands of mappings, and parsing
11676 // them is expensive, so we only want to do it if we must.
11677 //
11678 // Each object in the arrays is of the form:
11679 //
11680 // {
11681 // generatedLine: The line number in the generated code,
11682 // generatedColumn: The column number in the generated code,
11683 // source: The path to the original source file that generated this
11684 // chunk of code,
11685 // originalLine: The line number in the original source that
11686 // corresponds to this chunk of generated code,
11687 // originalColumn: The column number in the original source that
11688 // corresponds to this chunk of generated code,
11689 // name: The name of the original symbol which generated this chunk of
11690 // code.
11691 // }
11692 //
11693 // All properties except for `generatedLine` and `generatedColumn` can be
11694 // `null`.
11695 //
11696 // `_generatedMappings` is ordered by the generated positions.
11697 //
11698 // `_originalMappings` is ordered by the original positions.
11699
11700 SourceMapConsumer.prototype.__generatedMappings = null;
11701 Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', {
11702 get: function () {
11703 if (!this.__generatedMappings) {
11704 this._parseMappings(this._mappings, this.sourceRoot);
11705 }
11706
11707 return this.__generatedMappings;
11708 }
11709 });
11710
11711 SourceMapConsumer.prototype.__originalMappings = null;
11712 Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', {
11713 get: function () {
11714 if (!this.__originalMappings) {
11715 this._parseMappings(this._mappings, this.sourceRoot);
11716 }
11717
11718 return this.__originalMappings;
11719 }
11720 });
11721
11722 SourceMapConsumer.prototype._charIsMappingSeparator =
11723 function SourceMapConsumer_charIsMappingSeparator(aStr, index) {
11724 var c = aStr.charAt(index);
11725 return c === ";" || c === ",";
11726 };
11727
11728 /**
11729 * Parse the mappings in a string in to a data structure which we can easily
11730 * query (the ordered arrays in the `this.__generatedMappings` and
11731 * `this.__originalMappings` properties).
11732 */
11733 SourceMapConsumer.prototype._parseMappings =
11734 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
11735 throw new Error("Subclasses must implement _parseMappings");
11736 };
11737
11738 SourceMapConsumer.GENERATED_ORDER = 1;
11739 SourceMapConsumer.ORIGINAL_ORDER = 2;
11740
11741 SourceMapConsumer.GREATEST_LOWER_BOUND = 1;
11742 SourceMapConsumer.LEAST_UPPER_BOUND = 2;
11743
11744 /**
11745 * Iterate over each mapping between an original source/line/column and a
11746 * generated line/column in this source map.
11747 *
11748 * @param Function aCallback
11749 * The function that is called with each mapping.
11750 * @param Object aContext
11751 * Optional. If specified, this object will be the value of `this` every
11752 * time that `aCallback` is called.
11753 * @param aOrder
11754 * Either `SourceMapConsumer.GENERATED_ORDER` or
11755 * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
11756 * iterate over the mappings sorted by the generated file's line/column
11757 * order or the original's source/line/column order, respectively. Defaults to
11758 * `SourceMapConsumer.GENERATED_ORDER`.
11759 */
11760 SourceMapConsumer.prototype.eachMapping =
11761 function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
11762 var context = aContext || null;
11763 var order = aOrder || SourceMapConsumer.GENERATED_ORDER;
11764
11765 var mappings;
11766 switch (order) {
11767 case SourceMapConsumer.GENERATED_ORDER:
11768 mappings = this._generatedMappings;
11769 break;
11770 case SourceMapConsumer.ORIGINAL_ORDER:
11771 mappings = this._originalMappings;
11772 break;
11773 default:
11774 throw new Error("Unknown order of iteration.");
11775 }
11776
11777 var sourceRoot = this.sourceRoot;
11778 mappings.map(function (mapping) {
11779 var source = mapping.source === null ? null : this._sources.at(mapping.source);
11780 if (source != null && sourceRoot != null) {
11781 source = util.join(sourceRoot, source);
11782 }
11783 return {
11784 source: source,
11785 generatedLine: mapping.generatedLine,
11786 generatedColumn: mapping.generatedColumn,
11787 originalLine: mapping.originalLine,
11788 originalColumn: mapping.originalColumn,
11789 name: mapping.name === null ? null : this._names.at(mapping.name)
11790 };
11791 }, this).forEach(aCallback, context);
11792 };
11793
11794 /**
11795 * Returns all generated line and column information for the original source,
11796 * line, and column provided. If no column is provided, returns all mappings
11797 * corresponding to a either the line we are searching for or the next
11798 * closest line that has any mappings. Otherwise, returns all mappings
11799 * corresponding to the given line and either the column we are searching for
11800 * or the next closest column that has any offsets.
11801 *
11802 * The only argument is an object with the following properties:
11803 *
11804 * - source: The filename of the original source.
11805 * - line: The line number in the original source.
11806 * - column: Optional. the column number in the original source.
11807 *
11808 * and an array of objects is returned, each with the following properties:
11809 *
11810 * - line: The line number in the generated source, or null.
11811 * - column: The column number in the generated source, or null.
11812 */
11813 SourceMapConsumer.prototype.allGeneratedPositionsFor =
11814 function SourceMapConsumer_allGeneratedPositionsFor(aArgs) {
11815 var line = util.getArg(aArgs, 'line');
11816
11817 // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping
11818 // returns the index of the closest mapping less than the needle. By
11819 // setting needle.originalColumn to 0, we thus find the last mapping for
11820 // the given line, provided such a mapping exists.
11821 var needle = {
11822 source: util.getArg(aArgs, 'source'),
11823 originalLine: line,
11824 originalColumn: util.getArg(aArgs, 'column', 0)
11825 };
11826
11827 if (this.sourceRoot != null) {
11828 needle.source = util.relative(this.sourceRoot, needle.source);
11829 }
11830 if (!this._sources.has(needle.source)) {
11831 return [];
11832 }
11833 needle.source = this._sources.indexOf(needle.source);
11834
11835 var mappings = [];
11836
11837 var index = this._findMapping(needle,
11838 this._originalMappings,
11839 "originalLine",
11840 "originalColumn",
11841 util.compareByOriginalPositions,
11842 binarySearch.LEAST_UPPER_BOUND);
11843 if (index >= 0) {
11844 var mapping = this._originalMappings[index];
11845
11846 if (aArgs.column === undefined) {
11847 var originalLine = mapping.originalLine;
11848
11849 // Iterate until either we run out of mappings, or we run into
11850 // a mapping for a different line than the one we found. Since
11851 // mappings are sorted, this is guaranteed to find all mappings for
11852 // the line we found.
11853 while (mapping && mapping.originalLine === originalLine) {
11854 mappings.push({
11855 line: util.getArg(mapping, 'generatedLine', null),
11856 column: util.getArg(mapping, 'generatedColumn', null),
11857 lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
11858 });
11859
11860 mapping = this._originalMappings[++index];
11861 }
11862 } else {
11863 var originalColumn = mapping.originalColumn;
11864
11865 // Iterate until either we run out of mappings, or we run into
11866 // a mapping for a different line than the one we were searching for.
11867 // Since mappings are sorted, this is guaranteed to find all mappings for
11868 // the line we are searching for.
11869 while (mapping &&
11870 mapping.originalLine === line &&
11871 mapping.originalColumn == originalColumn) {
11872 mappings.push({
11873 line: util.getArg(mapping, 'generatedLine', null),
11874 column: util.getArg(mapping, 'generatedColumn', null),
11875 lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
11876 });
11877
11878 mapping = this._originalMappings[++index];
11879 }
11880 }
11881 }
11882
11883 return mappings;
11884 };
11885
11886 exports.SourceMapConsumer = SourceMapConsumer;
11887
11888 /**
11889 * A BasicSourceMapConsumer instance represents a parsed source map which we can
11890 * query for information about the original file positions by giving it a file
11891 * position in the generated source.
11892 *
11893 * The only parameter is the raw source map (either as a JSON string, or
11894 * already parsed to an object). According to the spec, source maps have the
11895 * following attributes:
11896 *
11897 * - version: Which version of the source map spec this map is following.
11898 * - sources: An array of URLs to the original source files.
11899 * - names: An array of identifiers which can be referrenced by individual mappings.
11900 * - sourceRoot: Optional. The URL root from which all sources are relative.
11901 * - sourcesContent: Optional. An array of contents of the original source files.
11902 * - mappings: A string of base64 VLQs which contain the actual mappings.
11903 * - file: Optional. The generated file this source map is associated with.
11904 *
11905 * Here is an example source map, taken from the source map spec[0]:
11906 *
11907 * {
11908 * version : 3,
11909 * file: "out.js",
11910 * sourceRoot : "",
11911 * sources: ["foo.js", "bar.js"],
11912 * names: ["src", "maps", "are", "fun"],
11913 * mappings: "AA,AB;;ABCDE;"
11914 * }
11915 *
11916 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
11917 */
11918 function BasicSourceMapConsumer(aSourceMap) {
11919 var sourceMap = aSourceMap;
11920 if (typeof aSourceMap === 'string') {
11921 sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
11922 }
11923
11924 var version = util.getArg(sourceMap, 'version');
11925 var sources = util.getArg(sourceMap, 'sources');
11926 // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which
11927 // requires the array) to play nice here.
11928 var names = util.getArg(sourceMap, 'names', []);
11929 var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
11930 var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
11931 var mappings = util.getArg(sourceMap, 'mappings');
11932 var file = util.getArg(sourceMap, 'file', null);
11933
11934 // Once again, Sass deviates from the spec and supplies the version as a
11935 // string rather than a number, so we use loose equality checking here.
11936 if (version != this._version) {
11937 throw new Error('Unsupported version: ' + version);
11938 }
11939
11940 sources = sources
11941 // Some source maps produce relative source paths like "./foo.js" instead of
11942 // "foo.js". Normalize these first so that future comparisons will succeed.
11943 // See bugzil.la/1090768.
11944 .map(util.normalize)
11945 // Always ensure that absolute sources are internally stored relative to
11946 // the source root, if the source root is absolute. Not doing this would
11947 // be particularly problematic when the source root is a prefix of the
11948 // source (valid, but why??). See github issue #199 and bugzil.la/1188982.
11949 .map(function (source) {
11950 return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source)
11951 ? util.relative(sourceRoot, source)
11952 : source;
11953 });
11954
11955 // Pass `true` below to allow duplicate names and sources. While source maps
11956 // are intended to be compressed and deduplicated, the TypeScript compiler
11957 // sometimes generates source maps with duplicates in them. See Github issue
11958 // #72 and bugzil.la/889492.
11959 this._names = ArraySet.fromArray(names, true);
11960 this._sources = ArraySet.fromArray(sources, true);
11961
11962 this.sourceRoot = sourceRoot;
11963 this.sourcesContent = sourcesContent;
11964 this._mappings = mappings;
11965 this.file = file;
11966 }
11967
11968 BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
11969 BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer;
11970
11971 /**
11972 * Create a BasicSourceMapConsumer from a SourceMapGenerator.
11973 *
11974 * @param SourceMapGenerator aSourceMap
11975 * The source map that will be consumed.
11976 * @returns BasicSourceMapConsumer
11977 */
11978 BasicSourceMapConsumer.fromSourceMap =
11979 function SourceMapConsumer_fromSourceMap(aSourceMap) {
11980 var smc = Object.create(BasicSourceMapConsumer.prototype);
11981
11982 var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true);
11983 var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true);
11984 smc.sourceRoot = aSourceMap._sourceRoot;
11985 smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(),
11986 smc.sourceRoot);
11987 smc.file = aSourceMap._file;
11988
11989 // Because we are modifying the entries (by converting string sources and
11990 // names to indices into the sources and names ArraySets), we have to make
11991 // a copy of the entry or else bad things happen. Shared mutable state
11992 // strikes again! See github issue #191.
11993
11994 var generatedMappings = aSourceMap._mappings.toArray().slice();
11995 var destGeneratedMappings = smc.__generatedMappings = [];
11996 var destOriginalMappings = smc.__originalMappings = [];
11997
11998 for (var i = 0, length = generatedMappings.length; i < length; i++) {
11999 var srcMapping = generatedMappings[i];
12000 var destMapping = new Mapping;
12001 destMapping.generatedLine = srcMapping.generatedLine;
12002 destMapping.generatedColumn = srcMapping.generatedColumn;
12003
12004 if (srcMapping.source) {
12005 destMapping.source = sources.indexOf(srcMapping.source);
12006 destMapping.originalLine = srcMapping.originalLine;
12007 destMapping.originalColumn = srcMapping.originalColumn;
12008
12009 if (srcMapping.name) {
12010 destMapping.name = names.indexOf(srcMapping.name);
12011 }
12012
12013 destOriginalMappings.push(destMapping);
12014 }
12015
12016 destGeneratedMappings.push(destMapping);
12017 }
12018
12019 quickSort(smc.__originalMappings, util.compareByOriginalPositions);
12020
12021 return smc;
12022 };
12023
12024 /**
12025 * The version of the source mapping spec that we are consuming.
12026 */
12027 BasicSourceMapConsumer.prototype._version = 3;
12028
12029 /**
12030 * The list of original sources.
12031 */
12032 Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', {
12033 get: function () {
12034 return this._sources.toArray().map(function (s) {
12035 return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s;
12036 }, this);
12037 }
12038 });
12039
12040 /**
12041 * Provide the JIT with a nice shape / hidden class.
12042 */
12043 function Mapping() {
12044 this.generatedLine = 0;
12045 this.generatedColumn = 0;
12046 this.source = null;
12047 this.originalLine = null;
12048 this.originalColumn = null;
12049 this.name = null;
12050 }
12051
12052 /**
12053 * Parse the mappings in a string in to a data structure which we can easily
12054 * query (the ordered arrays in the `this.__generatedMappings` and
12055 * `this.__originalMappings` properties).
12056 */
12057 BasicSourceMapConsumer.prototype._parseMappings =
12058 function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
12059 var generatedLine = 1;
12060 var previousGeneratedColumn = 0;
12061 var previousOriginalLine = 0;
12062 var previousOriginalColumn = 0;
12063 var previousSource = 0;
12064 var previousName = 0;
12065 var length = aStr.length;
12066 var index = 0;
12067 var cachedSegments = {};
12068 var temp = {};
12069 var originalMappings = [];
12070 var generatedMappings = [];
12071 var mapping, str, segment, end, value;
12072
12073 while (index < length) {
12074 if (aStr.charAt(index) === ';') {
12075 generatedLine++;
12076 index++;
12077 previousGeneratedColumn = 0;
12078 }
12079 else if (aStr.charAt(index) === ',') {
12080 index++;
12081 }
12082 else {
12083 mapping = new Mapping();
12084 mapping.generatedLine = generatedLine;
12085
12086 // Because each offset is encoded relative to the previous one,
12087 // many segments often have the same encoding. We can exploit this
12088 // fact by caching the parsed variable length fields of each segment,
12089 // allowing us to avoid a second parse if we encounter the same
12090 // segment again.
12091 for (end = index; end < length; end++) {
12092 if (this._charIsMappingSeparator(aStr, end)) {
12093 break;
12094 }
12095 }
12096 str = aStr.slice(index, end);
12097
12098 segment = cachedSegments[str];
12099 if (segment) {
12100 index += str.length;
12101 } else {
12102 segment = [];
12103 while (index < end) {
12104 base64VLQ.decode(aStr, index, temp);
12105 value = temp.value;
12106 index = temp.rest;
12107 segment.push(value);
12108 }
12109
12110 if (segment.length === 2) {
12111 throw new Error('Found a source, but no line and column');
12112 }
12113
12114 if (segment.length === 3) {
12115 throw new Error('Found a source and line, but no column');
12116 }
12117
12118 cachedSegments[str] = segment;
12119 }
12120
12121 // Generated column.
12122 mapping.generatedColumn = previousGeneratedColumn + segment[0];
12123 previousGeneratedColumn = mapping.generatedColumn;
12124
12125 if (segment.length > 1) {
12126 // Original source.
12127 mapping.source = previousSource + segment[1];
12128 previousSource += segment[1];
12129
12130 // Original line.
12131 mapping.originalLine = previousOriginalLine + segment[2];
12132 previousOriginalLine = mapping.originalLine;
12133 // Lines are stored 0-based
12134 mapping.originalLine += 1;
12135
12136 // Original column.
12137 mapping.originalColumn = previousOriginalColumn + segment[3];
12138 previousOriginalColumn = mapping.originalColumn;
12139
12140 if (segment.length > 4) {
12141 // Original name.
12142 mapping.name = previousName + segment[4];
12143 previousName += segment[4];
12144 }
12145 }
12146
12147 generatedMappings.push(mapping);
12148 if (typeof mapping.originalLine === 'number') {
12149 originalMappings.push(mapping);
12150 }
12151 }
12152 }
12153
12154 quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated);
12155 this.__generatedMappings = generatedMappings;
12156
12157 quickSort(originalMappings, util.compareByOriginalPositions);
12158 this.__originalMappings = originalMappings;
12159 };
12160
12161 /**
12162 * Find the mapping that best matches the hypothetical "needle" mapping that
12163 * we are searching for in the given "haystack" of mappings.
12164 */
12165 BasicSourceMapConsumer.prototype._findMapping =
12166 function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
12167 aColumnName, aComparator, aBias) {
12168 // To return the position we are searching for, we must first find the
12169 // mapping for the given position and then return the opposite position it
12170 // points to. Because the mappings are sorted, we can use binary search to
12171 // find the best mapping.
12172
12173 if (aNeedle[aLineName] <= 0) {
12174 throw new TypeError('Line must be greater than or equal to 1, got '
12175 + aNeedle[aLineName]);
12176 }
12177 if (aNeedle[aColumnName] < 0) {
12178 throw new TypeError('Column must be greater than or equal to 0, got '
12179 + aNeedle[aColumnName]);
12180 }
12181
12182 return binarySearch.search(aNeedle, aMappings, aComparator, aBias);
12183 };
12184
12185 /**
12186 * Compute the last column for each generated mapping. The last column is
12187 * inclusive.
12188 */
12189 BasicSourceMapConsumer.prototype.computeColumnSpans =
12190 function SourceMapConsumer_computeColumnSpans() {
12191 for (var index = 0; index < this._generatedMappings.length; ++index) {
12192 var mapping = this._generatedMappings[index];
12193
12194 // Mappings do not contain a field for the last generated columnt. We
12195 // can come up with an optimistic estimate, however, by assuming that
12196 // mappings are contiguous (i.e. given two consecutive mappings, the
12197 // first mapping ends where the second one starts).
12198 if (index + 1 < this._generatedMappings.length) {
12199 var nextMapping = this._generatedMappings[index + 1];
12200
12201 if (mapping.generatedLine === nextMapping.generatedLine) {
12202 mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1;
12203 continue;
12204 }
12205 }
12206
12207 // The last mapping for each line spans the entire line.
12208 mapping.lastGeneratedColumn = Infinity;
12209 }
12210 };
12211
12212 /**
12213 * Returns the original source, line, and column information for the generated
12214 * source's line and column positions provided. The only argument is an object
12215 * with the following properties:
12216 *
12217 * - line: The line number in the generated source.
12218 * - column: The column number in the generated source.
12219 * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
12220 * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
12221 * closest element that is smaller than or greater than the one we are
12222 * searching for, respectively, if the exact element cannot be found.
12223 * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
12224 *
12225 * and an object is returned with the following properties:
12226 *
12227 * - source: The original source file, or null.
12228 * - line: The line number in the original source, or null.
12229 * - column: The column number in the original source, or null.
12230 * - name: The original identifier, or null.
12231 */
12232 BasicSourceMapConsumer.prototype.originalPositionFor =
12233 function SourceMapConsumer_originalPositionFor(aArgs) {
12234 var needle = {
12235 generatedLine: util.getArg(aArgs, 'line'),
12236 generatedColumn: util.getArg(aArgs, 'column')
12237 };
12238
12239 var index = this._findMapping(
12240 needle,
12241 this._generatedMappings,
12242 "generatedLine",
12243 "generatedColumn",
12244 util.compareByGeneratedPositionsDeflated,
12245 util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND)
12246 );
12247
12248 if (index >= 0) {
12249 var mapping = this._generatedMappings[index];
12250
12251 if (mapping.generatedLine === needle.generatedLine) {
12252 var source = util.getArg(mapping, 'source', null);
12253 if (source !== null) {
12254 source = this._sources.at(source);
12255 if (this.sourceRoot != null) {
12256 source = util.join(this.sourceRoot, source);
12257 }
12258 }
12259 var name = util.getArg(mapping, 'name', null);
12260 if (name !== null) {
12261 name = this._names.at(name);
12262 }
12263 return {
12264 source: source,
12265 line: util.getArg(mapping, 'originalLine', null),
12266 column: util.getArg(mapping, 'originalColumn', null),
12267 name: name
12268 };
12269 }
12270 }
12271
12272 return {
12273 source: null,
12274 line: null,
12275 column: null,
12276 name: null
12277 };
12278 };
12279
12280 /**
12281 * Return true if we have the source content for every source in the source
12282 * map, false otherwise.
12283 */
12284 BasicSourceMapConsumer.prototype.hasContentsOfAllSources =
12285 function BasicSourceMapConsumer_hasContentsOfAllSources() {
12286 if (!this.sourcesContent) {
12287 return false;
12288 }
12289 return this.sourcesContent.length >= this._sources.size() &&
12290 !this.sourcesContent.some(function (sc) { return sc == null; });
12291 };
12292
12293 /**
12294 * Returns the original source content. The only argument is the url of the
12295 * original source file. Returns null if no original source content is
12296 * available.
12297 */
12298 BasicSourceMapConsumer.prototype.sourceContentFor =
12299 function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
12300 if (!this.sourcesContent) {
12301 return null;
12302 }
12303
12304 if (this.sourceRoot != null) {
12305 aSource = util.relative(this.sourceRoot, aSource);
12306 }
12307
12308 if (this._sources.has(aSource)) {
12309 return this.sourcesContent[this._sources.indexOf(aSource)];
12310 }
12311
12312 var url;
12313 if (this.sourceRoot != null
12314 && (url = util.urlParse(this.sourceRoot))) {
12315 // XXX: file:// URIs and absolute paths lead to unexpected behavior for
12316 // many users. We can help them out when they expect file:// URIs to
12317 // behave like it would if they were running a local HTTP server. See
12318 // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
12319 var fileUriAbsPath = aSource.replace(/^file:\/\//, "");
12320 if (url.scheme == "file"
12321 && this._sources.has(fileUriAbsPath)) {
12322 return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
12323 }
12324
12325 if ((!url.path || url.path == "/")
12326 && this._sources.has("/" + aSource)) {
12327 return this.sourcesContent[this._sources.indexOf("/" + aSource)];
12328 }
12329 }
12330
12331 // This function is used recursively from
12332 // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we
12333 // don't want to throw if we can't find the source - we just want to
12334 // return null, so we provide a flag to exit gracefully.
12335 if (nullOnMissing) {
12336 return null;
12337 }
12338 else {
12339 throw new Error('"' + aSource + '" is not in the SourceMap.');
12340 }
12341 };
12342
12343 /**
12344 * Returns the generated line and column information for the original source,
12345 * line, and column positions provided. The only argument is an object with
12346 * the following properties:
12347 *
12348 * - source: The filename of the original source.
12349 * - line: The line number in the original source.
12350 * - column: The column number in the original source.
12351 * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or
12352 * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the
12353 * closest element that is smaller than or greater than the one we are
12354 * searching for, respectively, if the exact element cannot be found.
12355 * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'.
12356 *
12357 * and an object is returned with the following properties:
12358 *
12359 * - line: The line number in the generated source, or null.
12360 * - column: The column number in the generated source, or null.
12361 */
12362 BasicSourceMapConsumer.prototype.generatedPositionFor =
12363 function SourceMapConsumer_generatedPositionFor(aArgs) {
12364 var source = util.getArg(aArgs, 'source');
12365 if (this.sourceRoot != null) {
12366 source = util.relative(this.sourceRoot, source);
12367 }
12368 if (!this._sources.has(source)) {
12369 return {
12370 line: null,
12371 column: null,
12372 lastColumn: null
12373 };
12374 }
12375 source = this._sources.indexOf(source);
12376
12377 var needle = {
12378 source: source,
12379 originalLine: util.getArg(aArgs, 'line'),
12380 originalColumn: util.getArg(aArgs, 'column')
12381 };
12382
12383 var index = this._findMapping(
12384 needle,
12385 this._originalMappings,
12386 "originalLine",
12387 "originalColumn",
12388 util.compareByOriginalPositions,
12389 util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND)
12390 );
12391
12392 if (index >= 0) {
12393 var mapping = this._originalMappings[index];
12394
12395 if (mapping.source === needle.source) {
12396 return {
12397 line: util.getArg(mapping, 'generatedLine', null),
12398 column: util.getArg(mapping, 'generatedColumn', null),
12399 lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null)
12400 };
12401 }
12402 }
12403
12404 return {
12405 line: null,
12406 column: null,
12407 lastColumn: null
12408 };
12409 };
12410
12411 exports.BasicSourceMapConsumer = BasicSourceMapConsumer;
12412
12413 /**
12414 * An IndexedSourceMapConsumer instance represents a parsed source map which
12415 * we can query for information. It differs from BasicSourceMapConsumer in
12416 * that it takes "indexed" source maps (i.e. ones with a "sections" field) as
12417 * input.
12418 *
12419 * The only parameter is a raw source map (either as a JSON string, or already
12420 * parsed to an object). According to the spec for indexed source maps, they
12421 * have the following attributes:
12422 *
12423 * - version: Which version of the source map spec this map is following.
12424 * - file: Optional. The generated file this source map is associated with.
12425 * - sections: A list of section definitions.
12426 *
12427 * Each value under the "sections" field has two fields:
12428 * - offset: The offset into the original specified at which this section
12429 * begins to apply, defined as an object with a "line" and "column"
12430 * field.
12431 * - map: A source map definition. This source map could also be indexed,
12432 * but doesn't have to be.
12433 *
12434 * Instead of the "map" field, it's also possible to have a "url" field
12435 * specifying a URL to retrieve a source map from, but that's currently
12436 * unsupported.
12437 *
12438 * Here's an example source map, taken from the source map spec[0], but
12439 * modified to omit a section which uses the "url" field.
12440 *
12441 * {
12442 * version : 3,
12443 * file: "app.js",
12444 * sections: [{
12445 * offset: {line:100, column:10},
12446 * map: {
12447 * version : 3,
12448 * file: "section.js",
12449 * sources: ["foo.js", "bar.js"],
12450 * names: ["src", "maps", "are", "fun"],
12451 * mappings: "AAAA,E;;ABCDE;"
12452 * }
12453 * }],
12454 * }
12455 *
12456 * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt
12457 */
12458 function IndexedSourceMapConsumer(aSourceMap) {
12459 var sourceMap = aSourceMap;
12460 if (typeof aSourceMap === 'string') {
12461 sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
12462 }
12463
12464 var version = util.getArg(sourceMap, 'version');
12465 var sections = util.getArg(sourceMap, 'sections');
12466
12467 if (version != this._version) {
12468 throw new Error('Unsupported version: ' + version);
12469 }
12470
12471 this._sources = new ArraySet();
12472 this._names = new ArraySet();
12473
12474 var lastOffset = {
12475 line: -1,
12476 column: 0
12477 };
12478 this._sections = sections.map(function (s) {
12479 if (s.url) {
12480 // The url field will require support for asynchronicity.
12481 // See https://github.com/mozilla/source-map/issues/16
12482 throw new Error('Support for url field in sections not implemented.');
12483 }
12484 var offset = util.getArg(s, 'offset');
12485 var offsetLine = util.getArg(offset, 'line');
12486 var offsetColumn = util.getArg(offset, 'column');
12487
12488 if (offsetLine < lastOffset.line ||
12489 (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) {
12490 throw new Error('Section offsets must be ordered and non-overlapping.');
12491 }
12492 lastOffset = offset;
12493
12494 return {
12495 generatedOffset: {
12496 // The offset fields are 0-based, but we use 1-based indices when
12497 // encoding/decoding from VLQ.
12498 generatedLine: offsetLine + 1,
12499 generatedColumn: offsetColumn + 1
12500 },
12501 consumer: new SourceMapConsumer(util.getArg(s, 'map'))
12502 }
12503 });
12504 }
12505
12506 IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype);
12507 IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer;
12508
12509 /**
12510 * The version of the source mapping spec that we are consuming.
12511 */
12512 IndexedSourceMapConsumer.prototype._version = 3;
12513
12514 /**
12515 * The list of original sources.
12516 */
12517 Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', {
12518 get: function () {
12519 var sources = [];
12520 for (var i = 0; i < this._sections.length; i++) {
12521 for (var j = 0; j < this._sections[i].consumer.sources.length; j++) {
12522 sources.push(this._sections[i].consumer.sources[j]);
12523 }
12524 }
12525 return sources;
12526 }
12527 });
12528
12529 /**
12530 * Returns the original source, line, and column information for the generated
12531 * source's line and column positions provided. The only argument is an object
12532 * with the following properties:
12533 *
12534 * - line: The line number in the generated source.
12535 * - column: The column number in the generated source.
12536 *
12537 * and an object is returned with the following properties:
12538 *
12539 * - source: The original source file, or null.
12540 * - line: The line number in the original source, or null.
12541 * - column: The column number in the original source, or null.
12542 * - name: The original identifier, or null.
12543 */
12544 IndexedSourceMapConsumer.prototype.originalPositionFor =
12545 function IndexedSourceMapConsumer_originalPositionFor(aArgs) {
12546 var needle = {
12547 generatedLine: util.getArg(aArgs, 'line'),
12548 generatedColumn: util.getArg(aArgs, 'column')
12549 };
12550
12551 // Find the section containing the generated position we're trying to map
12552 // to an original position.
12553 var sectionIndex = binarySearch.search(needle, this._sections,
12554 function(needle, section) {
12555 var cmp = needle.generatedLine - section.generatedOffset.generatedLine;
12556 if (cmp) {
12557 return cmp;
12558 }
12559
12560 return (needle.generatedColumn -
12561 section.generatedOffset.generatedColumn);
12562 });
12563 var section = this._sections[sectionIndex];
12564
12565 if (!section) {
12566 return {
12567 source: null,
12568 line: null,
12569 column: null,
12570 name: null
12571 };
12572 }
12573
12574 return section.consumer.originalPositionFor({
12575 line: needle.generatedLine -
12576 (section.generatedOffset.generatedLine - 1),
12577 column: needle.generatedColumn -
12578 (section.generatedOffset.generatedLine === needle.generatedLine
12579 ? section.generatedOffset.generatedColumn - 1
12580 : 0),
12581 bias: aArgs.bias
12582 });
12583 };
12584
12585 /**
12586 * Return true if we have the source content for every source in the source
12587 * map, false otherwise.
12588 */
12589 IndexedSourceMapConsumer.prototype.hasContentsOfAllSources =
12590 function IndexedSourceMapConsumer_hasContentsOfAllSources() {
12591 return this._sections.every(function (s) {
12592 return s.consumer.hasContentsOfAllSources();
12593 });
12594 };
12595
12596 /**
12597 * Returns the original source content. The only argument is the url of the
12598 * original source file. Returns null if no original source content is
12599 * available.
12600 */
12601 IndexedSourceMapConsumer.prototype.sourceContentFor =
12602 function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) {
12603 for (var i = 0; i < this._sections.length; i++) {
12604 var section = this._sections[i];
12605
12606 var content = section.consumer.sourceContentFor(aSource, true);
12607 if (content) {
12608 return content;
12609 }
12610 }
12611 if (nullOnMissing) {
12612 return null;
12613 }
12614 else {
12615 throw new Error('"' + aSource + '" is not in the SourceMap.');
12616 }
12617 };
12618
12619 /**
12620 * Returns the generated line and column information for the original source,
12621 * line, and column positions provided. The only argument is an object with
12622 * the following properties:
12623 *
12624 * - source: The filename of the original source.
12625 * - line: The line number in the original source.
12626 * - column: The column number in the original source.
12627 *
12628 * and an object is returned with the following properties:
12629 *
12630 * - line: The line number in the generated source, or null.
12631 * - column: The column number in the generated source, or null.
12632 */
12633 IndexedSourceMapConsumer.prototype.generatedPositionFor =
12634 function IndexedSourceMapConsumer_generatedPositionFor(aArgs) {
12635 for (var i = 0; i < this._sections.length; i++) {
12636 var section = this._sections[i];
12637
12638 // Only consider this section if the requested source is in the list of
12639 // sources of the consumer.
12640 if (section.consumer.sources.indexOf(util.getArg(aArgs, 'source')) === -1) {
12641 continue;
12642 }
12643 var generatedPosition = section.consumer.generatedPositionFor(aArgs);
12644 if (generatedPosition) {
12645 var ret = {
12646 line: generatedPosition.line +
12647 (section.generatedOffset.generatedLine - 1),
12648 column: generatedPosition.column +
12649 (section.generatedOffset.generatedLine === generatedPosition.line
12650 ? section.generatedOffset.generatedColumn - 1
12651 : 0)
12652 };
12653 return ret;
12654 }
12655 }
12656
12657 return {
12658 line: null,
12659 column: null
12660 };
12661 };
12662
12663 /**
12664 * Parse the mappings in a string in to a data structure which we can easily
12665 * query (the ordered arrays in the `this.__generatedMappings` and
12666 * `this.__originalMappings` properties).
12667 */
12668 IndexedSourceMapConsumer.prototype._parseMappings =
12669 function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) {
12670 this.__generatedMappings = [];
12671 this.__originalMappings = [];
12672 for (var i = 0; i < this._sections.length; i++) {
12673 var section = this._sections[i];
12674 var sectionMappings = section.consumer._generatedMappings;
12675 for (var j = 0; j < sectionMappings.length; j++) {
12676 var mapping = sectionMappings[j];
12677
12678 var source = section.consumer._sources.at(mapping.source);
12679 if (section.consumer.sourceRoot !== null) {
12680 source = util.join(section.consumer.sourceRoot, source);
12681 }
12682 this._sources.add(source);
12683 source = this._sources.indexOf(source);
12684
12685 var name = section.consumer._names.at(mapping.name);
12686 this._names.add(name);
12687 name = this._names.indexOf(name);
12688
12689 // The mappings coming from the consumer for the section have
12690 // generated positions relative to the start of the section, so we
12691 // need to offset them to be relative to the start of the concatenated
12692 // generated file.
12693 var adjustedMapping = {
12694 source: source,
12695 generatedLine: mapping.generatedLine +
12696 (section.generatedOffset.generatedLine - 1),
12697 generatedColumn: mapping.generatedColumn +
12698 (section.generatedOffset.generatedLine === mapping.generatedLine
12699 ? section.generatedOffset.generatedColumn - 1
12700 : 0),
12701 originalLine: mapping.originalLine,
12702 originalColumn: mapping.originalColumn,
12703 name: name
12704 };
12705
12706 this.__generatedMappings.push(adjustedMapping);
12707 if (typeof adjustedMapping.originalLine === 'number') {
12708 this.__originalMappings.push(adjustedMapping);
12709 }
12710 }
12711 }
12712
12713 quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated);
12714 quickSort(this.__originalMappings, util.compareByOriginalPositions);
12715 };
12716
12717 exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer;
12718 }
12719
12720
12721/***/ },
12722/* 8 */
12723/***/ function(module, exports) {
12724
12725 /* -*- Mode: js; js-indent-level: 2; -*- */
12726 /*
12727 * Copyright 2011 Mozilla Foundation and contributors
12728 * Licensed under the New BSD license. See LICENSE or:
12729 * http://opensource.org/licenses/BSD-3-Clause
12730 */
12731 {
12732 exports.GREATEST_LOWER_BOUND = 1;
12733 exports.LEAST_UPPER_BOUND = 2;
12734
12735 /**
12736 * Recursive implementation of binary search.
12737 *
12738 * @param aLow Indices here and lower do not contain the needle.
12739 * @param aHigh Indices here and higher do not contain the needle.
12740 * @param aNeedle The element being searched for.
12741 * @param aHaystack The non-empty array being searched.
12742 * @param aCompare Function which takes two elements and returns -1, 0, or 1.
12743 * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or
12744 * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the
12745 * closest element that is smaller than or greater than the one we are
12746 * searching for, respectively, if the exact element cannot be found.
12747 */
12748 function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) {
12749 // This function terminates when one of the following is true:
12750 //
12751 // 1. We find the exact element we are looking for.
12752 //
12753 // 2. We did not find the exact element, but we can return the index of
12754 // the next-closest element.
12755 //
12756 // 3. We did not find the exact element, and there is no next-closest
12757 // element than the one we are searching for, so we return -1.
12758 var mid = Math.floor((aHigh - aLow) / 2) + aLow;
12759 var cmp = aCompare(aNeedle, aHaystack[mid], true);
12760 if (cmp === 0) {
12761 // Found the element we are looking for.
12762 return mid;
12763 }
12764 else if (cmp > 0) {
12765 // Our needle is greater than aHaystack[mid].
12766 if (aHigh - mid > 1) {
12767 // The element is in the upper half.
12768 return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias);
12769 }
12770
12771 // The exact needle element was not found in this haystack. Determine if
12772 // we are in termination case (3) or (2) and return the appropriate thing.
12773 if (aBias == exports.LEAST_UPPER_BOUND) {
12774 return aHigh < aHaystack.length ? aHigh : -1;
12775 } else {
12776 return mid;
12777 }
12778 }
12779 else {
12780 // Our needle is less than aHaystack[mid].
12781 if (mid - aLow > 1) {
12782 // The element is in the lower half.
12783 return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias);
12784 }
12785
12786 // we are in termination case (3) or (2) and return the appropriate thing.
12787 if (aBias == exports.LEAST_UPPER_BOUND) {
12788 return mid;
12789 } else {
12790 return aLow < 0 ? -1 : aLow;
12791 }
12792 }
12793 }
12794
12795 /**
12796 * This is an implementation of binary search which will always try and return
12797 * the index of the closest element if there is no exact hit. This is because
12798 * mappings between original and generated line/col pairs are single points,
12799 * and there is an implicit region between each of them, so a miss just means
12800 * that you aren't on the very start of a region.
12801 *
12802 * @param aNeedle The element you are looking for.
12803 * @param aHaystack The array that is being searched.
12804 * @param aCompare A function which takes the needle and an element in the
12805 * array and returns -1, 0, or 1 depending on whether the needle is less
12806 * than, equal to, or greater than the element, respectively.
12807 * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or
12808 * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the
12809 * closest element that is smaller than or greater than the one we are
12810 * searching for, respectively, if the exact element cannot be found.
12811 * Defaults to 'binarySearch.GREATEST_LOWER_BOUND'.
12812 */
12813 exports.search = function search(aNeedle, aHaystack, aCompare, aBias) {
12814 if (aHaystack.length === 0) {
12815 return -1;
12816 }
12817
12818 var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack,
12819 aCompare, aBias || exports.GREATEST_LOWER_BOUND);
12820 if (index < 0) {
12821 return -1;
12822 }
12823
12824 // We have found either the exact element, or the next-closest element than
12825 // the one we are searching for. However, there may be more than one such
12826 // element. Make sure we always return the smallest of these.
12827 while (index - 1 >= 0) {
12828 if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) {
12829 break;
12830 }
12831 --index;
12832 }
12833
12834 return index;
12835 };
12836 }
12837
12838
12839/***/ },
12840/* 9 */
12841/***/ function(module, exports) {
12842
12843 /* -*- Mode: js; js-indent-level: 2; -*- */
12844 /*
12845 * Copyright 2011 Mozilla Foundation and contributors
12846 * Licensed under the New BSD license. See LICENSE or:
12847 * http://opensource.org/licenses/BSD-3-Clause
12848 */
12849 {
12850 // It turns out that some (most?) JavaScript engines don't self-host
12851 // `Array.prototype.sort`. This makes sense because C++ will likely remain
12852 // faster than JS when doing raw CPU-intensive sorting. However, when using a
12853 // custom comparator function, calling back and forth between the VM's C++ and
12854 // JIT'd JS is rather slow *and* loses JIT type information, resulting in
12855 // worse generated code for the comparator function than would be optimal. In
12856 // fact, when sorting with a comparator, these costs outweigh the benefits of
12857 // sorting in C++. By using our own JS-implemented Quick Sort (below), we get
12858 // a ~3500ms mean speed-up in `bench/bench.html`.
12859
12860 /**
12861 * Swap the elements indexed by `x` and `y` in the array `ary`.
12862 *
12863 * @param {Array} ary
12864 * The array.
12865 * @param {Number} x
12866 * The index of the first item.
12867 * @param {Number} y
12868 * The index of the second item.
12869 */
12870 function swap(ary, x, y) {
12871 var temp = ary[x];
12872 ary[x] = ary[y];
12873 ary[y] = temp;
12874 }
12875
12876 /**
12877 * Returns a random integer within the range `low .. high` inclusive.
12878 *
12879 * @param {Number} low
12880 * The lower bound on the range.
12881 * @param {Number} high
12882 * The upper bound on the range.
12883 */
12884 function randomIntInRange(low, high) {
12885 return Math.round(low + (Math.random() * (high - low)));
12886 }
12887
12888 /**
12889 * The Quick Sort algorithm.
12890 *
12891 * @param {Array} ary
12892 * An array to sort.
12893 * @param {function} comparator
12894 * Function to use to compare two items.
12895 * @param {Number} p
12896 * Start index of the array
12897 * @param {Number} r
12898 * End index of the array
12899 */
12900 function doQuickSort(ary, comparator, p, r) {
12901 // If our lower bound is less than our upper bound, we (1) partition the
12902 // array into two pieces and (2) recurse on each half. If it is not, this is
12903 // the empty array and our base case.
12904
12905 if (p < r) {
12906 // (1) Partitioning.
12907 //
12908 // The partitioning chooses a pivot between `p` and `r` and moves all
12909 // elements that are less than or equal to the pivot to the before it, and
12910 // all the elements that are greater than it after it. The effect is that
12911 // once partition is done, the pivot is in the exact place it will be when
12912 // the array is put in sorted order, and it will not need to be moved
12913 // again. This runs in O(n) time.
12914
12915 // Always choose a random pivot so that an input array which is reverse
12916 // sorted does not cause O(n^2) running time.
12917 var pivotIndex = randomIntInRange(p, r);
12918 var i = p - 1;
12919
12920 swap(ary, pivotIndex, r);
12921 var pivot = ary[r];
12922
12923 // Immediately after `j` is incremented in this loop, the following hold
12924 // true:
12925 //
12926 // * Every element in `ary[p .. i]` is less than or equal to the pivot.
12927 //
12928 // * Every element in `ary[i+1 .. j-1]` is greater than the pivot.
12929 for (var j = p; j < r; j++) {
12930 if (comparator(ary[j], pivot) <= 0) {
12931 i += 1;
12932 swap(ary, i, j);
12933 }
12934 }
12935
12936 swap(ary, i + 1, j);
12937 var q = i + 1;
12938
12939 // (2) Recurse on each half.
12940
12941 doQuickSort(ary, comparator, p, q - 1);
12942 doQuickSort(ary, comparator, q + 1, r);
12943 }
12944 }
12945
12946 /**
12947 * Sort the given array in-place with the given comparator function.
12948 *
12949 * @param {Array} ary
12950 * An array to sort.
12951 * @param {function} comparator
12952 * Function to use to compare two items.
12953 */
12954 exports.quickSort = function (ary, comparator) {
12955 doQuickSort(ary, comparator, 0, ary.length - 1);
12956 };
12957 }
12958
12959
12960/***/ },
12961/* 10 */
12962/***/ function(module, exports, __webpack_require__) {
12963
12964 /* -*- Mode: js; js-indent-level: 2; -*- */
12965 /*
12966 * Copyright 2011 Mozilla Foundation and contributors
12967 * Licensed under the New BSD license. See LICENSE or:
12968 * http://opensource.org/licenses/BSD-3-Clause
12969 */
12970 {
12971 var SourceMapGenerator = __webpack_require__(1).SourceMapGenerator;
12972 var util = __webpack_require__(4);
12973
12974 // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
12975 // operating systems these days (capturing the result).
12976 var REGEX_NEWLINE = /(\r?\n)/;
12977
12978 // Newline character code for charCodeAt() comparisons
12979 var NEWLINE_CODE = 10;
12980
12981 // Private symbol for identifying `SourceNode`s when multiple versions of
12982 // the source-map library are loaded. This MUST NOT CHANGE across
12983 // versions!
12984 var isSourceNode = "$$$isSourceNode$$$";
12985
12986 /**
12987 * SourceNodes provide a way to abstract over interpolating/concatenating
12988 * snippets of generated JavaScript source code while maintaining the line and
12989 * column information associated with the original source code.
12990 *
12991 * @param aLine The original line number.
12992 * @param aColumn The original column number.
12993 * @param aSource The original source's filename.
12994 * @param aChunks Optional. An array of strings which are snippets of
12995 * generated JS, or other SourceNodes.
12996 * @param aName The original identifier.
12997 */
12998 function SourceNode(aLine, aColumn, aSource, aChunks, aName) {
12999 this.children = [];
13000 this.sourceContents = {};
13001 this.line = aLine == null ? null : aLine;
13002 this.column = aColumn == null ? null : aColumn;
13003 this.source = aSource == null ? null : aSource;
13004 this.name = aName == null ? null : aName;
13005 this[isSourceNode] = true;
13006 if (aChunks != null) this.add(aChunks);
13007 }
13008
13009 /**
13010 * Creates a SourceNode from generated code and a SourceMapConsumer.
13011 *
13012 * @param aGeneratedCode The generated code
13013 * @param aSourceMapConsumer The SourceMap for the generated code
13014 * @param aRelativePath Optional. The path that relative sources in the
13015 * SourceMapConsumer should be relative to.
13016 */
13017 SourceNode.fromStringWithSourceMap =
13018 function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) {
13019 // The SourceNode we want to fill with the generated code
13020 // and the SourceMap
13021 var node = new SourceNode();
13022
13023 // All even indices of this array are one line of the generated code,
13024 // while all odd indices are the newlines between two adjacent lines
13025 // (since `REGEX_NEWLINE` captures its match).
13026 // Processed fragments are removed from this array, by calling `shiftNextLine`.
13027 var remainingLines = aGeneratedCode.split(REGEX_NEWLINE);
13028 var shiftNextLine = function() {
13029 var lineContents = remainingLines.shift();
13030 // The last line of a file might not have a newline.
13031 var newLine = remainingLines.shift() || "";
13032 return lineContents + newLine;
13033 };
13034
13035 // We need to remember the position of "remainingLines"
13036 var lastGeneratedLine = 1, lastGeneratedColumn = 0;
13037
13038 // The generate SourceNodes we need a code range.
13039 // To extract it current and last mapping is used.
13040 // Here we store the last mapping.
13041 var lastMapping = null;
13042
13043 aSourceMapConsumer.eachMapping(function (mapping) {
13044 if (lastMapping !== null) {
13045 // We add the code from "lastMapping" to "mapping":
13046 // First check if there is a new line in between.
13047 if (lastGeneratedLine < mapping.generatedLine) {
13048 // Associate first line with "lastMapping"
13049 addMappingWithCode(lastMapping, shiftNextLine());
13050 lastGeneratedLine++;
13051 lastGeneratedColumn = 0;
13052 // The remaining code is added without mapping
13053 } else {
13054 // There is no new line in between.
13055 // Associate the code between "lastGeneratedColumn" and
13056 // "mapping.generatedColumn" with "lastMapping"
13057 var nextLine = remainingLines[0];
13058 var code = nextLine.substr(0, mapping.generatedColumn -
13059 lastGeneratedColumn);
13060 remainingLines[0] = nextLine.substr(mapping.generatedColumn -
13061 lastGeneratedColumn);
13062 lastGeneratedColumn = mapping.generatedColumn;
13063 addMappingWithCode(lastMapping, code);
13064 // No more remaining code, continue
13065 lastMapping = mapping;
13066 return;
13067 }
13068 }
13069 // We add the generated code until the first mapping
13070 // to the SourceNode without any mapping.
13071 // Each line is added as separate string.
13072 while (lastGeneratedLine < mapping.generatedLine) {
13073 node.add(shiftNextLine());
13074 lastGeneratedLine++;
13075 }
13076 if (lastGeneratedColumn < mapping.generatedColumn) {
13077 var nextLine = remainingLines[0];
13078 node.add(nextLine.substr(0, mapping.generatedColumn));
13079 remainingLines[0] = nextLine.substr(mapping.generatedColumn);
13080 lastGeneratedColumn = mapping.generatedColumn;
13081 }
13082 lastMapping = mapping;
13083 }, this);
13084 // We have processed all mappings.
13085 if (remainingLines.length > 0) {
13086 if (lastMapping) {
13087 // Associate the remaining code in the current line with "lastMapping"
13088 addMappingWithCode(lastMapping, shiftNextLine());
13089 }
13090 // and add the remaining lines without any mapping
13091 node.add(remainingLines.join(""));
13092 }
13093
13094 // Copy sourcesContent into SourceNode
13095 aSourceMapConsumer.sources.forEach(function (sourceFile) {
13096 var content = aSourceMapConsumer.sourceContentFor(sourceFile);
13097 if (content != null) {
13098 if (aRelativePath != null) {
13099 sourceFile = util.join(aRelativePath, sourceFile);
13100 }
13101 node.setSourceContent(sourceFile, content);
13102 }
13103 });
13104
13105 return node;
13106
13107 function addMappingWithCode(mapping, code) {
13108 if (mapping === null || mapping.source === undefined) {
13109 node.add(code);
13110 } else {
13111 var source = aRelativePath
13112 ? util.join(aRelativePath, mapping.source)
13113 : mapping.source;
13114 node.add(new SourceNode(mapping.originalLine,
13115 mapping.originalColumn,
13116 source,
13117 code,
13118 mapping.name));
13119 }
13120 }
13121 };
13122
13123 /**
13124 * Add a chunk of generated JS to this source node.
13125 *
13126 * @param aChunk A string snippet of generated JS code, another instance of
13127 * SourceNode, or an array where each member is one of those things.
13128 */
13129 SourceNode.prototype.add = function SourceNode_add(aChunk) {
13130 if (Array.isArray(aChunk)) {
13131 aChunk.forEach(function (chunk) {
13132 this.add(chunk);
13133 }, this);
13134 }
13135 else if (aChunk[isSourceNode] || typeof aChunk === "string") {
13136 if (aChunk) {
13137 this.children.push(aChunk);
13138 }
13139 }
13140 else {
13141 throw new TypeError(
13142 "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
13143 );
13144 }
13145 return this;
13146 };
13147
13148 /**
13149 * Add a chunk of generated JS to the beginning of this source node.
13150 *
13151 * @param aChunk A string snippet of generated JS code, another instance of
13152 * SourceNode, or an array where each member is one of those things.
13153 */
13154 SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) {
13155 if (Array.isArray(aChunk)) {
13156 for (var i = aChunk.length-1; i >= 0; i--) {
13157 this.prepend(aChunk[i]);
13158 }
13159 }
13160 else if (aChunk[isSourceNode] || typeof aChunk === "string") {
13161 this.children.unshift(aChunk);
13162 }
13163 else {
13164 throw new TypeError(
13165 "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk
13166 );
13167 }
13168 return this;
13169 };
13170
13171 /**
13172 * Walk over the tree of JS snippets in this node and its children. The
13173 * walking function is called once for each snippet of JS and is passed that
13174 * snippet and the its original associated source's line/column location.
13175 *
13176 * @param aFn The traversal function.
13177 */
13178 SourceNode.prototype.walk = function SourceNode_walk(aFn) {
13179 var chunk;
13180 for (var i = 0, len = this.children.length; i < len; i++) {
13181 chunk = this.children[i];
13182 if (chunk[isSourceNode]) {
13183 chunk.walk(aFn);
13184 }
13185 else {
13186 if (chunk !== '') {
13187 aFn(chunk, { source: this.source,
13188 line: this.line,
13189 column: this.column,
13190 name: this.name });
13191 }
13192 }
13193 }
13194 };
13195
13196 /**
13197 * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between
13198 * each of `this.children`.
13199 *
13200 * @param aSep The separator.
13201 */
13202 SourceNode.prototype.join = function SourceNode_join(aSep) {
13203 var newChildren;
13204 var i;
13205 var len = this.children.length;
13206 if (len > 0) {
13207 newChildren = [];
13208 for (i = 0; i < len-1; i++) {
13209 newChildren.push(this.children[i]);
13210 newChildren.push(aSep);
13211 }
13212 newChildren.push(this.children[i]);
13213 this.children = newChildren;
13214 }
13215 return this;
13216 };
13217
13218 /**
13219 * Call String.prototype.replace on the very right-most source snippet. Useful
13220 * for trimming whitespace from the end of a source node, etc.
13221 *
13222 * @param aPattern The pattern to replace.
13223 * @param aReplacement The thing to replace the pattern with.
13224 */
13225 SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) {
13226 var lastChild = this.children[this.children.length - 1];
13227 if (lastChild[isSourceNode]) {
13228 lastChild.replaceRight(aPattern, aReplacement);
13229 }
13230 else if (typeof lastChild === 'string') {
13231 this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement);
13232 }
13233 else {
13234 this.children.push(''.replace(aPattern, aReplacement));
13235 }
13236 return this;
13237 };
13238
13239 /**
13240 * Set the source content for a source file. This will be added to the SourceMapGenerator
13241 * in the sourcesContent field.
13242 *
13243 * @param aSourceFile The filename of the source file
13244 * @param aSourceContent The content of the source file
13245 */
13246 SourceNode.prototype.setSourceContent =
13247 function SourceNode_setSourceContent(aSourceFile, aSourceContent) {
13248 this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent;
13249 };
13250
13251 /**
13252 * Walk over the tree of SourceNodes. The walking function is called for each
13253 * source file content and is passed the filename and source content.
13254 *
13255 * @param aFn The traversal function.
13256 */
13257 SourceNode.prototype.walkSourceContents =
13258 function SourceNode_walkSourceContents(aFn) {
13259 for (var i = 0, len = this.children.length; i < len; i++) {
13260 if (this.children[i][isSourceNode]) {
13261 this.children[i].walkSourceContents(aFn);
13262 }
13263 }
13264
13265 var sources = Object.keys(this.sourceContents);
13266 for (var i = 0, len = sources.length; i < len; i++) {
13267 aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]);
13268 }
13269 };
13270
13271 /**
13272 * Return the string representation of this source node. Walks over the tree
13273 * and concatenates all the various snippets together to one string.
13274 */
13275 SourceNode.prototype.toString = function SourceNode_toString() {
13276 var str = "";
13277 this.walk(function (chunk) {
13278 str += chunk;
13279 });
13280 return str;
13281 };
13282
13283 /**
13284 * Returns the string representation of this source node along with a source
13285 * map.
13286 */
13287 SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) {
13288 var generated = {
13289 code: "",
13290 line: 1,
13291 column: 0
13292 };
13293 var map = new SourceMapGenerator(aArgs);
13294 var sourceMappingActive = false;
13295 var lastOriginalSource = null;
13296 var lastOriginalLine = null;
13297 var lastOriginalColumn = null;
13298 var lastOriginalName = null;
13299 this.walk(function (chunk, original) {
13300 generated.code += chunk;
13301 if (original.source !== null
13302 && original.line !== null
13303 && original.column !== null) {
13304 if(lastOriginalSource !== original.source
13305 || lastOriginalLine !== original.line
13306 || lastOriginalColumn !== original.column
13307 || lastOriginalName !== original.name) {
13308 map.addMapping({
13309 source: original.source,
13310 original: {
13311 line: original.line,
13312 column: original.column
13313 },
13314 generated: {
13315 line: generated.line,
13316 column: generated.column
13317 },
13318 name: original.name
13319 });
13320 }
13321 lastOriginalSource = original.source;
13322 lastOriginalLine = original.line;
13323 lastOriginalColumn = original.column;
13324 lastOriginalName = original.name;
13325 sourceMappingActive = true;
13326 } else if (sourceMappingActive) {
13327 map.addMapping({
13328 generated: {
13329 line: generated.line,
13330 column: generated.column
13331 }
13332 });
13333 lastOriginalSource = null;
13334 sourceMappingActive = false;
13335 }
13336 for (var idx = 0, length = chunk.length; idx < length; idx++) {
13337 if (chunk.charCodeAt(idx) === NEWLINE_CODE) {
13338 generated.line++;
13339 generated.column = 0;
13340 // Mappings end at eol
13341 if (idx + 1 === length) {
13342 lastOriginalSource = null;
13343 sourceMappingActive = false;
13344 } else if (sourceMappingActive) {
13345 map.addMapping({
13346 source: original.source,
13347 original: {
13348 line: original.line,
13349 column: original.column
13350 },
13351 generated: {
13352 line: generated.line,
13353 column: generated.column
13354 },
13355 name: original.name
13356 });
13357 }
13358 } else {
13359 generated.column++;
13360 }
13361 }
13362 });
13363 this.walkSourceContents(function (sourceFile, sourceContent) {
13364 map.setSourceContent(sourceFile, sourceContent);
13365 });
13366
13367 return { code: generated.code, map: map };
13368 };
13369
13370 exports.SourceNode = SourceNode;
13371 }
13372
13373
13374/***/ }
13375/******/ ])
13376});
13377;define('uglifyjs/consolidator', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
13378/**
13379 * @preserve Copyright 2012 Robert Gust-Bardon <http://robert.gust-bardon.org/>.
13380 * All rights reserved.
13381 *
13382 * Redistribution and use in source and binary forms, with or without
13383 * modification, are permitted provided that the following conditions
13384 * are met:
13385 *
13386 * * Redistributions of source code must retain the above
13387 * copyright notice, this list of conditions and the following
13388 * disclaimer.
13389 *
13390 * * Redistributions in binary form must reproduce the above
13391 * copyright notice, this list of conditions and the following
13392 * disclaimer in the documentation and/or other materials
13393 * provided with the distribution.
13394 *
13395 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
13396 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13397 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
13398 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
13399 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
13400 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
13401 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
13402 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13403 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
13404 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
13405 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13406 * SUCH DAMAGE.
13407 */
13408
13409/**
13410 * @fileoverview Enhances <a href="https://github.com/mishoo/UglifyJS/"
13411 * >UglifyJS</a> with consolidation of null, Boolean, and String values.
13412 * <p>Also known as aliasing, this feature has been deprecated in <a href=
13413 * "http://closure-compiler.googlecode.com/">the Closure Compiler</a> since its
13414 * initial release, where it is unavailable from the <abbr title=
13415 * "command line interface">CLI</a>. The Closure Compiler allows one to log and
13416 * influence this process. In contrast, this implementation does not introduce
13417 * any variable declarations in global code and derives String values from
13418 * identifier names used as property accessors.</p>
13419 * <p>Consolidating literals may worsen the data compression ratio when an <a
13420 * href="http://tools.ietf.org/html/rfc2616#section-3.5">encoding
13421 * transformation</a> is applied. For instance, <a href=
13422 * "http://code.jquery.com/jquery-1.7.1.js">jQuery 1.7.1</a> takes 248235 bytes.
13423 * Building it with <a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">
13424 * UglifyJS v1.2.5</a> results in 93647 bytes (37.73% of the original) which are
13425 * then compressed to 33154 bytes (13.36% of the original) using <a href=
13426 * "http://linux.die.net/man/1/gzip">gzip(1)</a>. Building it with the same
13427 * version of UglifyJS 1.2.5 patched with the implementation of consolidation
13428 * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison
13429 * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes
13430 * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned
13431 * 33154 bytes).</p>
13432 * <p>Written in <a href="http://es5.github.com/#x4.2.2">the strict variant</a>
13433 * of <a href="http://es5.github.com/">ECMA-262 5.1 Edition</a>. Encoded in <a
13434 * href="http://tools.ietf.org/html/rfc3629">UTF-8</a>. Follows <a href=
13435 * "http://google-styleguide.googlecode.com/svn-history/r76/trunk/javascriptguide.xml"
13436 * >Revision 2.28 of the Google JavaScript Style Guide</a> (except for the
13437 * discouraged use of the {@code function} tag and the {@code namespace} tag).
13438 * 100% typed for the <a href=
13439 * "http://closure-compiler.googlecode.com/files/compiler-20120123.tar.gz"
13440 * >Closure Compiler Version 1741</a>.</p>
13441 * <p>Should you find this software useful, please consider <a href=
13442 * "https://paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JZLW72X8FD4WG"
13443 * >a donation</a>.</p>
13444 * @author follow.me@RGustBardon (Robert Gust-Bardon)
13445 * @supported Tested with:
13446 * <ul>
13447 * <li><a href="http://nodejs.org/dist/v0.6.10/">Node v0.6.10</a>,</li>
13448 * <li><a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">UglifyJS
13449 * v1.2.5</a>.</li>
13450 * </ul>
13451 */
13452
13453/*global console:false, exports:true, module:false, require:false */
13454/*jshint sub:true */
13455/**
13456 * Consolidates null, Boolean, and String values found inside an <abbr title=
13457 * "abstract syntax tree">AST</abbr>.
13458 * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object
13459 * representing an <abbr title="abstract syntax tree">AST</abbr>.
13460 * @return {!TSyntacticCodeUnit} An array-like object representing an <abbr
13461 * title="abstract syntax tree">AST</abbr> with its null, Boolean, and
13462 * String values consolidated.
13463 */
13464// TODO(user) Consolidation of mathematical values found in numeric literals.
13465// TODO(user) Unconsolidation.
13466// TODO(user) Consolidation of ECMA-262 6th Edition programs.
13467// TODO(user) Rewrite in ECMA-262 6th Edition.
13468exports['ast_consolidate'] = function(oAbstractSyntaxTree) {
13469 'use strict';
13470 /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
13471 latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
13472 onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
13473 sub:false, trailing:true */
13474
13475 var _,
13476 /**
13477 * A record consisting of data about one or more source elements.
13478 * @constructor
13479 * @nosideeffects
13480 */
13481 TSourceElementsData = function() {
13482 /**
13483 * The category of the elements.
13484 * @type {number}
13485 * @see ESourceElementCategories
13486 */
13487 this.nCategory = ESourceElementCategories.N_OTHER;
13488 /**
13489 * The number of occurrences (within the elements) of each primitive
13490 * value that could be consolidated.
13491 * @type {!Array.<!Object.<string, number>>}
13492 */
13493 this.aCount = [];
13494 this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {};
13495 this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {};
13496 this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] =
13497 {};
13498 /**
13499 * Identifier names found within the elements.
13500 * @type {!Array.<string>}
13501 */
13502 this.aIdentifiers = [];
13503 /**
13504 * Prefixed representation Strings of each primitive value that could be
13505 * consolidated within the elements.
13506 * @type {!Array.<string>}
13507 */
13508 this.aPrimitiveValues = [];
13509 },
13510 /**
13511 * A record consisting of data about a primitive value that could be
13512 * consolidated.
13513 * @constructor
13514 * @nosideeffects
13515 */
13516 TPrimitiveValue = function() {
13517 /**
13518 * The difference in the number of terminal symbols between the original
13519 * source text and the one with the primitive value consolidated. If the
13520 * difference is positive, the primitive value is considered worthwhile.
13521 * @type {number}
13522 */
13523 this.nSaving = 0;
13524 /**
13525 * An identifier name of the variable that will be declared and assigned
13526 * the primitive value if the primitive value is consolidated.
13527 * @type {string}
13528 */
13529 this.sName = '';
13530 },
13531 /**
13532 * A record consisting of data on what to consolidate within the range of
13533 * source elements that is currently being considered.
13534 * @constructor
13535 * @nosideeffects
13536 */
13537 TSolution = function() {
13538 /**
13539 * An object whose keys are prefixed representation Strings of each
13540 * primitive value that could be consolidated within the elements and
13541 * whose values are corresponding data about those primitive values.
13542 * @type {!Object.<string, {nSaving: number, sName: string}>}
13543 * @see TPrimitiveValue
13544 */
13545 this.oPrimitiveValues = {};
13546 /**
13547 * The difference in the number of terminal symbols between the original
13548 * source text and the one with all the worthwhile primitive values
13549 * consolidated.
13550 * @type {number}
13551 * @see TPrimitiveValue#nSaving
13552 */
13553 this.nSavings = 0;
13554 },
13555 /**
13556 * The processor of <abbr title="abstract syntax tree">AST</abbr>s found
13557 * in UglifyJS.
13558 * @namespace
13559 * @type {!TProcessor}
13560 */
13561 oProcessor = (/** @type {!TProcessor} */ require('./process')),
13562 /**
13563 * A record consisting of a number of constants that represent the
13564 * difference in the number of terminal symbols between a source text with
13565 * a modified syntactic code unit and the original one.
13566 * @namespace
13567 * @type {!Object.<string, number>}
13568 */
13569 oWeights = {
13570 /**
13571 * The difference in the number of punctuators required by the bracket
13572 * notation and the dot notation.
13573 * <p><code>'[]'.length - '.'.length</code></p>
13574 * @const
13575 * @type {number}
13576 */
13577 N_PROPERTY_ACCESSOR: 1,
13578 /**
13579 * The number of punctuators required by a variable declaration with an
13580 * initialiser.
13581 * <p><code>':'.length + ';'.length</code></p>
13582 * @const
13583 * @type {number}
13584 */
13585 N_VARIABLE_DECLARATION: 2,
13586 /**
13587 * The number of terminal symbols required to introduce a variable
13588 * statement (excluding its variable declaration list).
13589 * <p><code>'var '.length</code></p>
13590 * @const
13591 * @type {number}
13592 */
13593 N_VARIABLE_STATEMENT_AFFIXATION: 4,
13594 /**
13595 * The number of terminal symbols needed to enclose source elements
13596 * within a function call with no argument values to a function with an
13597 * empty parameter list.
13598 * <p><code>'(function(){}());'.length</code></p>
13599 * @const
13600 * @type {number}
13601 */
13602 N_CLOSURE: 17
13603 },
13604 /**
13605 * Categories of primary expressions from which primitive values that
13606 * could be consolidated are derivable.
13607 * @namespace
13608 * @enum {number}
13609 */
13610 EPrimaryExpressionCategories = {
13611 /**
13612 * Identifier names used as property accessors.
13613 * @type {number}
13614 */
13615 N_IDENTIFIER_NAMES: 0,
13616 /**
13617 * String literals.
13618 * @type {number}
13619 */
13620 N_STRING_LITERALS: 1,
13621 /**
13622 * Null and Boolean literals.
13623 * @type {number}
13624 */
13625 N_NULL_AND_BOOLEAN_LITERALS: 2
13626 },
13627 /**
13628 * Prefixes of primitive values that could be consolidated.
13629 * The String values of the prefixes must have same number of characters.
13630 * The prefixes must not be used in any properties defined in any version
13631 * of <a href=
13632 * "http://www.ecma-international.org/publications/standards/Ecma-262.htm"
13633 * >ECMA-262</a>.
13634 * @namespace
13635 * @enum {string}
13636 */
13637 EValuePrefixes = {
13638 /**
13639 * Identifies String values.
13640 * @type {string}
13641 */
13642 S_STRING: '#S',
13643 /**
13644 * Identifies null and Boolean values.
13645 * @type {string}
13646 */
13647 S_SYMBOLIC: '#O'
13648 },
13649 /**
13650 * Categories of source elements in terms of their appropriateness of
13651 * having their primitive values consolidated.
13652 * @namespace
13653 * @enum {number}
13654 */
13655 ESourceElementCategories = {
13656 /**
13657 * Identifies a source element that includes the <a href=
13658 * "http://es5.github.com/#x12.10">{@code with}</a> statement.
13659 * @type {number}
13660 */
13661 N_WITH: 0,
13662 /**
13663 * Identifies a source element that includes the <a href=
13664 * "http://es5.github.com/#x15.1.2.1">{@code eval}</a> identifier name.
13665 * @type {number}
13666 */
13667 N_EVAL: 1,
13668 /**
13669 * Identifies a source element that must be excluded from the process
13670 * unless its whole scope is examined.
13671 * @type {number}
13672 */
13673 N_EXCLUDABLE: 2,
13674 /**
13675 * Identifies source elements not posing any problems.
13676 * @type {number}
13677 */
13678 N_OTHER: 3
13679 },
13680 /**
13681 * The list of literals (other than the String ones) whose primitive
13682 * values can be consolidated.
13683 * @const
13684 * @type {!Array.<string>}
13685 */
13686 A_OTHER_SUBSTITUTABLE_LITERALS = [
13687 'null', // The null literal.
13688 'false', // The Boolean literal {@code false}.
13689 'true' // The Boolean literal {@code true}.
13690 ];
13691
13692 (/**
13693 * Consolidates all worthwhile primitive values in a syntactic code unit.
13694 * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object
13695 * representing the branch of the abstract syntax tree representing the
13696 * syntactic code unit along with its scope.
13697 * @see TPrimitiveValue#nSaving
13698 */
13699 function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) {
13700 var _,
13701 /**
13702 * Indicates whether the syntactic code unit represents global code.
13703 * @type {boolean}
13704 */
13705 bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0],
13706 /**
13707 * Indicates whether the whole scope is being examined.
13708 * @type {boolean}
13709 */
13710 bIsWhollyExaminable = !bIsGlobal,
13711 /**
13712 * An array-like object representing source elements that constitute a
13713 * syntactic code unit.
13714 * @type {!TSyntacticCodeUnit}
13715 */
13716 oSourceElements,
13717 /**
13718 * A record consisting of data about the source element that is
13719 * currently being examined.
13720 * @type {!TSourceElementsData}
13721 */
13722 oSourceElementData,
13723 /**
13724 * The scope of the syntactic code unit.
13725 * @type {!TScope}
13726 */
13727 oScope,
13728 /**
13729 * An instance of an object that allows the traversal of an <abbr
13730 * title="abstract syntax tree">AST</abbr>.
13731 * @type {!TWalker}
13732 */
13733 oWalker,
13734 /**
13735 * An object encompassing collections of functions used during the
13736 * traversal of an <abbr title="abstract syntax tree">AST</abbr>.
13737 * @namespace
13738 * @type {!Object.<string, !Object.<string, function(...[*])>>}
13739 */
13740 oWalkers = {
13741 /**
13742 * A collection of functions used during the surveyance of source
13743 * elements.
13744 * @namespace
13745 * @type {!Object.<string, function(...[*])>}
13746 */
13747 oSurveySourceElement: {
13748 /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
13749 /**
13750 * Classifies the source element as excludable if it does not
13751 * contain a {@code with} statement or the {@code eval} identifier
13752 * name. Adds the identifier of the function and its formal
13753 * parameters to the list of identifier names found.
13754 * @param {string} sIdentifier The identifier of the function.
13755 * @param {!Array.<string>} aFormalParameterList Formal parameters.
13756 * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
13757 */
13758 'defun': function(
13759 sIdentifier,
13760 aFormalParameterList,
13761 oFunctionBody) {
13762 fClassifyAsExcludable();
13763 fAddIdentifier(sIdentifier);
13764 aFormalParameterList.forEach(fAddIdentifier);
13765 },
13766 /**
13767 * Increments the count of the number of occurrences of the String
13768 * value that is equivalent to the sequence of terminal symbols
13769 * that constitute the encountered identifier name.
13770 * @param {!TSyntacticCodeUnit} oExpression The nonterminal
13771 * MemberExpression.
13772 * @param {string} sIdentifierName The identifier name used as the
13773 * property accessor.
13774 * @return {!Array} The encountered branch of an <abbr title=
13775 * "abstract syntax tree">AST</abbr> with its nonterminal
13776 * MemberExpression traversed.
13777 */
13778 'dot': function(oExpression, sIdentifierName) {
13779 fCountPrimaryExpression(
13780 EPrimaryExpressionCategories.N_IDENTIFIER_NAMES,
13781 EValuePrefixes.S_STRING + sIdentifierName);
13782 return ['dot', oWalker.walk(oExpression), sIdentifierName];
13783 },
13784 /**
13785 * Adds the optional identifier of the function and its formal
13786 * parameters to the list of identifier names found.
13787 * @param {?string} sIdentifier The optional identifier of the
13788 * function.
13789 * @param {!Array.<string>} aFormalParameterList Formal parameters.
13790 * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
13791 */
13792 'function': function(
13793 sIdentifier,
13794 aFormalParameterList,
13795 oFunctionBody) {
13796 if ('string' === typeof sIdentifier) {
13797 fAddIdentifier(sIdentifier);
13798 }
13799 aFormalParameterList.forEach(fAddIdentifier);
13800 },
13801 /**
13802 * Either increments the count of the number of occurrences of the
13803 * encountered null or Boolean value or classifies a source element
13804 * as containing the {@code eval} identifier name.
13805 * @param {string} sIdentifier The identifier encountered.
13806 */
13807 'name': function(sIdentifier) {
13808 if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) {
13809 fCountPrimaryExpression(
13810 EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS,
13811 EValuePrefixes.S_SYMBOLIC + sIdentifier);
13812 } else {
13813 if ('eval' === sIdentifier) {
13814 oSourceElementData.nCategory =
13815 ESourceElementCategories.N_EVAL;
13816 }
13817 fAddIdentifier(sIdentifier);
13818 }
13819 },
13820 /**
13821 * Classifies the source element as excludable if it does not
13822 * contain a {@code with} statement or the {@code eval} identifier
13823 * name.
13824 * @param {TSyntacticCodeUnit} oExpression The expression whose
13825 * value is to be returned.
13826 */
13827 'return': function(oExpression) {
13828 fClassifyAsExcludable();
13829 },
13830 /**
13831 * Increments the count of the number of occurrences of the
13832 * encountered String value.
13833 * @param {string} sStringValue The String value of the string
13834 * literal encountered.
13835 */
13836 'string': function(sStringValue) {
13837 if (sStringValue.length > 0) {
13838 fCountPrimaryExpression(
13839 EPrimaryExpressionCategories.N_STRING_LITERALS,
13840 EValuePrefixes.S_STRING + sStringValue);
13841 }
13842 },
13843 /**
13844 * Adds the identifier reserved for an exception to the list of
13845 * identifier names found.
13846 * @param {!TSyntacticCodeUnit} oTry A block of code in which an
13847 * exception can occur.
13848 * @param {Array} aCatch The identifier reserved for an exception
13849 * and a block of code to handle the exception.
13850 * @param {TSyntacticCodeUnit} oFinally An optional block of code
13851 * to be evaluated regardless of whether an exception occurs.
13852 */
13853 'try': function(oTry, aCatch, oFinally) {
13854 if (Array.isArray(aCatch)) {
13855 fAddIdentifier(aCatch[0]);
13856 }
13857 },
13858 /**
13859 * Classifies the source element as excludable if it does not
13860 * contain a {@code with} statement or the {@code eval} identifier
13861 * name. Adds the identifier of each declared variable to the list
13862 * of identifier names found.
13863 * @param {!Array.<!Array>} aVariableDeclarationList Variable
13864 * declarations.
13865 */
13866 'var': function(aVariableDeclarationList) {
13867 fClassifyAsExcludable();
13868 aVariableDeclarationList.forEach(fAddVariable);
13869 },
13870 /**
13871 * Classifies a source element as containing the {@code with}
13872 * statement.
13873 * @param {!TSyntacticCodeUnit} oExpression An expression whose
13874 * value is to be converted to a value of type Object and
13875 * become the binding object of a new object environment
13876 * record of a new lexical environment in which the statement
13877 * is to be executed.
13878 * @param {!TSyntacticCodeUnit} oStatement The statement to be
13879 * executed in the augmented lexical environment.
13880 * @return {!Array} An empty array to stop the traversal.
13881 */
13882 'with': function(oExpression, oStatement) {
13883 oSourceElementData.nCategory = ESourceElementCategories.N_WITH;
13884 return [];
13885 }
13886 /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
13887 },
13888 /**
13889 * A collection of functions used while looking for nested functions.
13890 * @namespace
13891 * @type {!Object.<string, function(...[*])>}
13892 */
13893 oExamineFunctions: {
13894 /**#nocode+*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
13895 /**
13896 * Orders an examination of a nested function declaration.
13897 * @this {!TSyntacticCodeUnit} An array-like object representing
13898 * the branch of an <abbr title="abstract syntax tree"
13899 * >AST</abbr> representing the syntactic code unit along with
13900 * its scope.
13901 * @return {!Array} An empty array to stop the traversal.
13902 */
13903 'defun': function() {
13904 fExamineSyntacticCodeUnit(this);
13905 return [];
13906 },
13907 /**
13908 * Orders an examination of a nested function expression.
13909 * @this {!TSyntacticCodeUnit} An array-like object representing
13910 * the branch of an <abbr title="abstract syntax tree"
13911 * >AST</abbr> representing the syntactic code unit along with
13912 * its scope.
13913 * @return {!Array} An empty array to stop the traversal.
13914 */
13915 'function': function() {
13916 fExamineSyntacticCodeUnit(this);
13917 return [];
13918 }
13919 /**#nocode-*/ // JsDoc Toolkit 2.4.0 hides some of the keys.
13920 }
13921 },
13922 /**
13923 * Records containing data about source elements.
13924 * @type {Array.<TSourceElementsData>}
13925 */
13926 aSourceElementsData = [],
13927 /**
13928 * The index (in the source text order) of the source element
13929 * immediately following a <a href="http://es5.github.com/#x14.1"
13930 * >Directive Prologue</a>.
13931 * @type {number}
13932 */
13933 nAfterDirectivePrologue = 0,
13934 /**
13935 * The index (in the source text order) of the source element that is
13936 * currently being considered.
13937 * @type {number}
13938 */
13939 nPosition,
13940 /**
13941 * The index (in the source text order) of the source element that is
13942 * the last element of the range of source elements that is currently
13943 * being considered.
13944 * @type {(undefined|number)}
13945 */
13946 nTo,
13947 /**
13948 * Initiates the traversal of a source element.
13949 * @param {!TWalker} oWalker An instance of an object that allows the
13950 * traversal of an abstract syntax tree.
13951 * @param {!TSyntacticCodeUnit} oSourceElement A source element from
13952 * which the traversal should commence.
13953 * @return {function(): !TSyntacticCodeUnit} A function that is able to
13954 * initiate the traversal from a given source element.
13955 */
13956 cContext = function(oWalker, oSourceElement) {
13957 /**
13958 * @return {!TSyntacticCodeUnit} A function that is able to
13959 * initiate the traversal from a given source element.
13960 */
13961 var fLambda = function() {
13962 return oWalker.walk(oSourceElement);
13963 };
13964
13965 return fLambda;
13966 },
13967 /**
13968 * Classifies the source element as excludable if it does not
13969 * contain a {@code with} statement or the {@code eval} identifier
13970 * name.
13971 */
13972 fClassifyAsExcludable = function() {
13973 if (oSourceElementData.nCategory ===
13974 ESourceElementCategories.N_OTHER) {
13975 oSourceElementData.nCategory =
13976 ESourceElementCategories.N_EXCLUDABLE;
13977 }
13978 },
13979 /**
13980 * Adds an identifier to the list of identifier names found.
13981 * @param {string} sIdentifier The identifier to be added.
13982 */
13983 fAddIdentifier = function(sIdentifier) {
13984 if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) {
13985 oSourceElementData.aIdentifiers.push(sIdentifier);
13986 }
13987 },
13988 /**
13989 * Adds the identifier of a variable to the list of identifier names
13990 * found.
13991 * @param {!Array} aVariableDeclaration A variable declaration.
13992 */
13993 fAddVariable = function(aVariableDeclaration) {
13994 fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]);
13995 },
13996 /**
13997 * Increments the count of the number of occurrences of the prefixed
13998 * String representation attributed to the primary expression.
13999 * @param {number} nCategory The category of the primary expression.
14000 * @param {string} sName The prefixed String representation attributed
14001 * to the primary expression.
14002 */
14003 fCountPrimaryExpression = function(nCategory, sName) {
14004 if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) {
14005 oSourceElementData.aCount[nCategory][sName] = 0;
14006 if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) {
14007 oSourceElementData.aPrimitiveValues.push(sName);
14008 }
14009 }
14010 oSourceElementData.aCount[nCategory][sName] += 1;
14011 },
14012 /**
14013 * Consolidates all worthwhile primitive values in a range of source
14014 * elements.
14015 * @param {number} nFrom The index (in the source text order) of the
14016 * source element that is the first element of the range.
14017 * @param {number} nTo The index (in the source text order) of the
14018 * source element that is the last element of the range.
14019 * @param {boolean} bEnclose Indicates whether the range should be
14020 * enclosed within a function call with no argument values to a
14021 * function with an empty parameter list if any primitive values
14022 * are consolidated.
14023 * @see TPrimitiveValue#nSaving
14024 */
14025 fExamineSourceElements = function(nFrom, nTo, bEnclose) {
14026 var _,
14027 /**
14028 * The index of the last mangled name.
14029 * @type {number}
14030 */
14031 nIndex = oScope.cname,
14032 /**
14033 * The index of the source element that is currently being
14034 * considered.
14035 * @type {number}
14036 */
14037 nPosition,
14038 /**
14039 * A collection of functions used during the consolidation of
14040 * primitive values and identifier names used as property
14041 * accessors.
14042 * @namespace
14043 * @type {!Object.<string, function(...[*])>}
14044 */
14045 oWalkersTransformers = {
14046 /**
14047 * If the String value that is equivalent to the sequence of
14048 * terminal symbols that constitute the encountered identifier
14049 * name is worthwhile, a syntactic conversion from the dot
14050 * notation to the bracket notation ensues with that sequence
14051 * being substituted by an identifier name to which the value
14052 * is assigned.
14053 * Applies to property accessors that use the dot notation.
14054 * @param {!TSyntacticCodeUnit} oExpression The nonterminal
14055 * MemberExpression.
14056 * @param {string} sIdentifierName The identifier name used as
14057 * the property accessor.
14058 * @return {!Array} A syntactic code unit that is equivalent to
14059 * the one encountered.
14060 * @see TPrimitiveValue#nSaving
14061 */
14062 'dot': function(oExpression, sIdentifierName) {
14063 /**
14064 * The prefixed String value that is equivalent to the
14065 * sequence of terminal symbols that constitute the
14066 * encountered identifier name.
14067 * @type {string}
14068 */
14069 var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName;
14070
14071 return oSolutionBest.oPrimitiveValues.hasOwnProperty(
14072 sPrefixed) &&
14073 oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
14074 ['sub',
14075 oWalker.walk(oExpression),
14076 ['name',
14077 oSolutionBest.oPrimitiveValues[sPrefixed].sName]] :
14078 ['dot', oWalker.walk(oExpression), sIdentifierName];
14079 },
14080 /**
14081 * If the encountered identifier is a null or Boolean literal
14082 * and its value is worthwhile, the identifier is substituted
14083 * by an identifier name to which that value is assigned.
14084 * Applies to identifier names.
14085 * @param {string} sIdentifier The identifier encountered.
14086 * @return {!Array} A syntactic code unit that is equivalent to
14087 * the one encountered.
14088 * @see TPrimitiveValue#nSaving
14089 */
14090 'name': function(sIdentifier) {
14091 /**
14092 * The prefixed representation String of the identifier.
14093 * @type {string}
14094 */
14095 var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier;
14096
14097 return [
14098 'name',
14099 oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) &&
14100 oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
14101 oSolutionBest.oPrimitiveValues[sPrefixed].sName :
14102 sIdentifier
14103 ];
14104 },
14105 /**
14106 * If the encountered String value is worthwhile, it is
14107 * substituted by an identifier name to which that value is
14108 * assigned.
14109 * Applies to String values.
14110 * @param {string} sStringValue The String value of the string
14111 * literal encountered.
14112 * @return {!Array} A syntactic code unit that is equivalent to
14113 * the one encountered.
14114 * @see TPrimitiveValue#nSaving
14115 */
14116 'string': function(sStringValue) {
14117 /**
14118 * The prefixed representation String of the primitive value
14119 * of the literal.
14120 * @type {string}
14121 */
14122 var sPrefixed =
14123 EValuePrefixes.S_STRING + sStringValue;
14124
14125 return oSolutionBest.oPrimitiveValues.hasOwnProperty(
14126 sPrefixed) &&
14127 oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
14128 ['name',
14129 oSolutionBest.oPrimitiveValues[sPrefixed].sName] :
14130 ['string', sStringValue];
14131 }
14132 },
14133 /**
14134 * Such data on what to consolidate within the range of source
14135 * elements that is currently being considered that lead to the
14136 * greatest known reduction of the number of the terminal symbols
14137 * in comparison to the original source text.
14138 * @type {!TSolution}
14139 */
14140 oSolutionBest = new TSolution(),
14141 /**
14142 * Data representing an ongoing attempt to find a better
14143 * reduction of the number of the terminal symbols in comparison
14144 * to the original source text than the best one that is
14145 * currently known.
14146 * @type {!TSolution}
14147 * @see oSolutionBest
14148 */
14149 oSolutionCandidate = new TSolution(),
14150 /**
14151 * A record consisting of data about the range of source elements
14152 * that is currently being examined.
14153 * @type {!TSourceElementsData}
14154 */
14155 oSourceElementsData = new TSourceElementsData(),
14156 /**
14157 * Variable declarations for each primitive value that is to be
14158 * consolidated within the elements.
14159 * @type {!Array.<!Array>}
14160 */
14161 aVariableDeclarations = [],
14162 /**
14163 * Augments a list with a prefixed representation String.
14164 * @param {!Array.<string>} aList A list that is to be augmented.
14165 * @return {function(string)} A function that augments a list
14166 * with a prefixed representation String.
14167 */
14168 cAugmentList = function(aList) {
14169 /**
14170 * @param {string} sPrefixed Prefixed representation String of
14171 * a primitive value that could be consolidated within the
14172 * elements.
14173 */
14174 var fLambda = function(sPrefixed) {
14175 if (-1 === aList.indexOf(sPrefixed)) {
14176 aList.push(sPrefixed);
14177 }
14178 };
14179
14180 return fLambda;
14181 },
14182 /**
14183 * Adds the number of occurrences of a primitive value of a given
14184 * category that could be consolidated in the source element with
14185 * a given index to the count of occurrences of that primitive
14186 * value within the range of source elements that is currently
14187 * being considered.
14188 * @param {number} nPosition The index (in the source text order)
14189 * of a source element.
14190 * @param {number} nCategory The category of the primary
14191 * expression from which the primitive value is derived.
14192 * @return {function(string)} A function that performs the
14193 * addition.
14194 * @see cAddOccurrencesInCategory
14195 */
14196 cAddOccurrences = function(nPosition, nCategory) {
14197 /**
14198 * @param {string} sPrefixed The prefixed representation String
14199 * of a primitive value.
14200 */
14201 var fLambda = function(sPrefixed) {
14202 if (!oSourceElementsData.aCount[nCategory].hasOwnProperty(
14203 sPrefixed)) {
14204 oSourceElementsData.aCount[nCategory][sPrefixed] = 0;
14205 }
14206 oSourceElementsData.aCount[nCategory][sPrefixed] +=
14207 aSourceElementsData[nPosition].aCount[nCategory][
14208 sPrefixed];
14209 };
14210
14211 return fLambda;
14212 },
14213 /**
14214 * Adds the number of occurrences of each primitive value of a
14215 * given category that could be consolidated in the source
14216 * element with a given index to the count of occurrences of that
14217 * primitive values within the range of source elements that is
14218 * currently being considered.
14219 * @param {number} nPosition The index (in the source text order)
14220 * of a source element.
14221 * @return {function(number)} A function that performs the
14222 * addition.
14223 * @see fAddOccurrences
14224 */
14225 cAddOccurrencesInCategory = function(nPosition) {
14226 /**
14227 * @param {number} nCategory The category of the primary
14228 * expression from which the primitive value is derived.
14229 */
14230 var fLambda = function(nCategory) {
14231 Object.keys(
14232 aSourceElementsData[nPosition].aCount[nCategory]
14233 ).forEach(cAddOccurrences(nPosition, nCategory));
14234 };
14235
14236 return fLambda;
14237 },
14238 /**
14239 * Adds the number of occurrences of each primitive value that
14240 * could be consolidated in the source element with a given index
14241 * to the count of occurrences of that primitive values within
14242 * the range of source elements that is currently being
14243 * considered.
14244 * @param {number} nPosition The index (in the source text order)
14245 * of a source element.
14246 */
14247 fAddOccurrences = function(nPosition) {
14248 Object.keys(aSourceElementsData[nPosition].aCount).forEach(
14249 cAddOccurrencesInCategory(nPosition));
14250 },
14251 /**
14252 * Creates a variable declaration for a primitive value if that
14253 * primitive value is to be consolidated within the elements.
14254 * @param {string} sPrefixed Prefixed representation String of a
14255 * primitive value that could be consolidated within the
14256 * elements.
14257 * @see aVariableDeclarations
14258 */
14259 cAugmentVariableDeclarations = function(sPrefixed) {
14260 if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) {
14261 aVariableDeclarations.push([
14262 oSolutionBest.oPrimitiveValues[sPrefixed].sName,
14263 [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ?
14264 'name' : 'string',
14265 sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)]
14266 ]);
14267 }
14268 },
14269 /**
14270 * Sorts primitive values with regard to the difference in the
14271 * number of terminal symbols between the original source text
14272 * and the one with those primitive values consolidated.
14273 * @param {string} sPrefixed0 The prefixed representation String
14274 * of the first of the two primitive values that are being
14275 * compared.
14276 * @param {string} sPrefixed1 The prefixed representation String
14277 * of the second of the two primitive values that are being
14278 * compared.
14279 * @return {number}
14280 * <dl>
14281 * <dt>-1</dt>
14282 * <dd>if the first primitive value must be placed before
14283 * the other one,</dd>
14284 * <dt>0</dt>
14285 * <dd>if the first primitive value may be placed before
14286 * the other one,</dd>
14287 * <dt>1</dt>
14288 * <dd>if the first primitive value must not be placed
14289 * before the other one.</dd>
14290 * </dl>
14291 * @see TSolution.oPrimitiveValues
14292 */
14293 cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) {
14294 /**
14295 * The difference between:
14296 * <ol>
14297 * <li>the difference in the number of terminal symbols
14298 * between the original source text and the one with the
14299 * first primitive value consolidated, and</li>
14300 * <li>the difference in the number of terminal symbols
14301 * between the original source text and the one with the
14302 * second primitive value consolidated.</li>
14303 * </ol>
14304 * @type {number}
14305 */
14306 var nDifference =
14307 oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving -
14308 oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving;
14309
14310 return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0;
14311 },
14312 /**
14313 * Assigns an identifier name to a primitive value and calculates
14314 * whether instances of that primitive value are worth
14315 * consolidating.
14316 * @param {string} sPrefixed The prefixed representation String
14317 * of a primitive value that is being evaluated.
14318 */
14319 fEvaluatePrimitiveValue = function(sPrefixed) {
14320 var _,
14321 /**
14322 * The index of the last mangled name.
14323 * @type {number}
14324 */
14325 nIndex,
14326 /**
14327 * The representation String of the primitive value that is
14328 * being evaluated.
14329 * @type {string}
14330 */
14331 sName =
14332 sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length),
14333 /**
14334 * The number of source characters taken up by the
14335 * representation String of the primitive value that is
14336 * being evaluated.
14337 * @type {number}
14338 */
14339 nLengthOriginal = sName.length,
14340 /**
14341 * The number of source characters taken up by the
14342 * identifier name that could substitute the primitive
14343 * value that is being evaluated.
14344 * substituted.
14345 * @type {number}
14346 */
14347 nLengthSubstitution,
14348 /**
14349 * The number of source characters taken up by by the
14350 * representation String of the primitive value that is
14351 * being evaluated when it is represented by a string
14352 * literal.
14353 * @type {number}
14354 */
14355 nLengthString = oProcessor.make_string(sName).length;
14356
14357 oSolutionCandidate.oPrimitiveValues[sPrefixed] =
14358 new TPrimitiveValue();
14359 do { // Find an identifier unused in this or any nested scope.
14360 nIndex = oScope.cname;
14361 oSolutionCandidate.oPrimitiveValues[sPrefixed].sName =
14362 oScope.next_mangled();
14363 } while (-1 !== oSourceElementsData.aIdentifiers.indexOf(
14364 oSolutionCandidate.oPrimitiveValues[sPrefixed].sName));
14365 nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[
14366 sPrefixed].sName.length;
14367 if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) {
14368 // foo:null, or foo:null;
14369 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
14370 nLengthSubstitution + nLengthOriginal +
14371 oWeights.N_VARIABLE_DECLARATION;
14372 // null vs foo
14373 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
14374 oSourceElementsData.aCount[
14375 EPrimaryExpressionCategories.
14376 N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] *
14377 (nLengthOriginal - nLengthSubstitution);
14378 } else {
14379 // foo:'fromCharCode';
14380 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
14381 nLengthSubstitution + nLengthString +
14382 oWeights.N_VARIABLE_DECLARATION;
14383 // .fromCharCode vs [foo]
14384 if (oSourceElementsData.aCount[
14385 EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
14386 ].hasOwnProperty(sPrefixed)) {
14387 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
14388 oSourceElementsData.aCount[
14389 EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
14390 ][sPrefixed] *
14391 (nLengthOriginal - nLengthSubstitution -
14392 oWeights.N_PROPERTY_ACCESSOR);
14393 }
14394 // 'fromCharCode' vs foo
14395 if (oSourceElementsData.aCount[
14396 EPrimaryExpressionCategories.N_STRING_LITERALS
14397 ].hasOwnProperty(sPrefixed)) {
14398 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
14399 oSourceElementsData.aCount[
14400 EPrimaryExpressionCategories.N_STRING_LITERALS
14401 ][sPrefixed] *
14402 (nLengthString - nLengthSubstitution);
14403 }
14404 }
14405 if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving >
14406 0) {
14407 oSolutionCandidate.nSavings +=
14408 oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving;
14409 } else {
14410 oScope.cname = nIndex; // Free the identifier name.
14411 }
14412 },
14413 /**
14414 * Adds a variable declaration to an existing variable statement.
14415 * @param {!Array} aVariableDeclaration A variable declaration
14416 * with an initialiser.
14417 */
14418 cAddVariableDeclaration = function(aVariableDeclaration) {
14419 (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift(
14420 aVariableDeclaration);
14421 };
14422
14423 if (nFrom > nTo) {
14424 return;
14425 }
14426 // If the range is a closure, reuse the closure.
14427 if (nFrom === nTo &&
14428 'stat' === oSourceElements[nFrom][0] &&
14429 'call' === oSourceElements[nFrom][1][0] &&
14430 'function' === oSourceElements[nFrom][1][1][0]) {
14431 fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]);
14432 return;
14433 }
14434 // Create a list of all derived primitive values within the range.
14435 for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
14436 aSourceElementsData[nPosition].aPrimitiveValues.forEach(
14437 cAugmentList(oSourceElementsData.aPrimitiveValues));
14438 }
14439 if (0 === oSourceElementsData.aPrimitiveValues.length) {
14440 return;
14441 }
14442 for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
14443 // Add the number of occurrences to the total count.
14444 fAddOccurrences(nPosition);
14445 // Add identifiers of this or any nested scope to the list.
14446 aSourceElementsData[nPosition].aIdentifiers.forEach(
14447 cAugmentList(oSourceElementsData.aIdentifiers));
14448 }
14449 // Distribute identifier names among derived primitive values.
14450 do { // If there was any progress, find a better distribution.
14451 oSolutionBest = oSolutionCandidate;
14452 if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) {
14453 // Sort primitive values descending by their worthwhileness.
14454 oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues);
14455 }
14456 oSolutionCandidate = new TSolution();
14457 oSourceElementsData.aPrimitiveValues.forEach(
14458 fEvaluatePrimitiveValue);
14459 oScope.cname = nIndex;
14460 } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings);
14461 // Take the necessity of adding a variable statement into account.
14462 if ('var' !== oSourceElements[nFrom][0]) {
14463 oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION;
14464 }
14465 if (bEnclose) {
14466 // Take the necessity of forming a closure into account.
14467 oSolutionBest.nSavings -= oWeights.N_CLOSURE;
14468 }
14469 if (oSolutionBest.nSavings > 0) {
14470 // Create variable declarations suitable for UglifyJS.
14471 Object.keys(oSolutionBest.oPrimitiveValues).forEach(
14472 cAugmentVariableDeclarations);
14473 // Rewrite expressions that contain worthwhile primitive values.
14474 for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
14475 oWalker = oProcessor.ast_walker();
14476 oSourceElements[nPosition] =
14477 oWalker.with_walkers(
14478 oWalkersTransformers,
14479 cContext(oWalker, oSourceElements[nPosition]));
14480 }
14481 if ('var' === oSourceElements[nFrom][0]) { // Reuse the statement.
14482 (/** @type {!Array.<!Array>} */ aVariableDeclarations.reverse(
14483 )).forEach(cAddVariableDeclaration);
14484 } else { // Add a variable statement.
14485 Array.prototype.splice.call(
14486 oSourceElements,
14487 nFrom,
14488 0,
14489 ['var', aVariableDeclarations]);
14490 nTo += 1;
14491 }
14492 if (bEnclose) {
14493 // Add a closure.
14494 Array.prototype.splice.call(
14495 oSourceElements,
14496 nFrom,
14497 0,
14498 ['stat', ['call', ['function', null, [], []], []]]);
14499 // Copy source elements into the closure.
14500 for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) {
14501 Array.prototype.unshift.call(
14502 oSourceElements[nFrom][1][1][3],
14503 oSourceElements[nPosition]);
14504 }
14505 // Remove source elements outside the closure.
14506 Array.prototype.splice.call(
14507 oSourceElements,
14508 nFrom + 1,
14509 nTo - nFrom + 1);
14510 }
14511 }
14512 if (bEnclose) {
14513 // Restore the availability of identifier names.
14514 oScope.cname = nIndex;
14515 }
14516 };
14517
14518 oSourceElements = (/** @type {!TSyntacticCodeUnit} */
14519 oSyntacticCodeUnit[bIsGlobal ? 1 : 3]);
14520 if (0 === oSourceElements.length) {
14521 return;
14522 }
14523 oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope;
14524 // Skip a Directive Prologue.
14525 while (nAfterDirectivePrologue < oSourceElements.length &&
14526 'directive' === oSourceElements[nAfterDirectivePrologue][0]) {
14527 nAfterDirectivePrologue += 1;
14528 aSourceElementsData.push(null);
14529 }
14530 if (oSourceElements.length === nAfterDirectivePrologue) {
14531 return;
14532 }
14533 for (nPosition = nAfterDirectivePrologue;
14534 nPosition < oSourceElements.length;
14535 nPosition += 1) {
14536 oSourceElementData = new TSourceElementsData();
14537 oWalker = oProcessor.ast_walker();
14538 // Classify a source element.
14539 // Find its derived primitive values and count their occurrences.
14540 // Find all identifiers used (including nested scopes).
14541 oWalker.with_walkers(
14542 oWalkers.oSurveySourceElement,
14543 cContext(oWalker, oSourceElements[nPosition]));
14544 // Establish whether the scope is still wholly examinable.
14545 bIsWhollyExaminable = bIsWhollyExaminable &&
14546 ESourceElementCategories.N_WITH !== oSourceElementData.nCategory &&
14547 ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory;
14548 aSourceElementsData.push(oSourceElementData);
14549 }
14550 if (bIsWhollyExaminable) { // Examine the whole scope.
14551 fExamineSourceElements(
14552 nAfterDirectivePrologue,
14553 oSourceElements.length - 1,
14554 false);
14555 } else { // Examine unexcluded ranges of source elements.
14556 for (nPosition = oSourceElements.length - 1;
14557 nPosition >= nAfterDirectivePrologue;
14558 nPosition -= 1) {
14559 oSourceElementData = (/** @type {!TSourceElementsData} */
14560 aSourceElementsData[nPosition]);
14561 if (ESourceElementCategories.N_OTHER ===
14562 oSourceElementData.nCategory) {
14563 if ('undefined' === typeof nTo) {
14564 nTo = nPosition; // Indicate the end of a range.
14565 }
14566 // Examine the range if it immediately follows a Directive Prologue.
14567 if (nPosition === nAfterDirectivePrologue) {
14568 fExamineSourceElements(nPosition, nTo, true);
14569 }
14570 } else {
14571 if ('undefined' !== typeof nTo) {
14572 // Examine the range that immediately follows this source element.
14573 fExamineSourceElements(nPosition + 1, nTo, true);
14574 nTo = void 0; // Obliterate the range.
14575 }
14576 // Examine nested functions.
14577 oWalker = oProcessor.ast_walker();
14578 oWalker.with_walkers(
14579 oWalkers.oExamineFunctions,
14580 cContext(oWalker, oSourceElements[nPosition]));
14581 }
14582 }
14583 }
14584 }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree)));
14585 return oAbstractSyntaxTree;
14586};
14587/*jshint sub:false */
14588
14589/* Local Variables: */
14590/* mode: js */
14591/* coding: utf-8 */
14592/* indent-tabs-mode: nil */
14593/* tab-width: 2 */
14594/* End: */
14595/* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */
14596/* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */
14597});
14598define('uglifyjs/parse-js', ["exports"], function(exports) {
14599/***********************************************************************
14600
14601 A JavaScript tokenizer / parser / beautifier / compressor.
14602
14603 This version is suitable for Node.js. With minimal changes (the
14604 exports stuff) it should work on any JS platform.
14605
14606 This file contains the tokenizer/parser. It is a port to JavaScript
14607 of parse-js [1], a JavaScript parser library written in Common Lisp
14608 by Marijn Haverbeke. Thank you Marijn!
14609
14610 [1] http://marijn.haverbeke.nl/parse-js/
14611
14612 Exported functions:
14613
14614 - tokenizer(code) -- returns a function. Call the returned
14615 function to fetch the next token.
14616
14617 - parse(code) -- returns an AST of the given JavaScript code.
14618
14619 -------------------------------- (C) ---------------------------------
14620
14621 Author: Mihai Bazon
14622 <mihai.bazon@gmail.com>
14623 http://mihai.bazon.net/blog
14624
14625 Distributed under the BSD license:
14626
14627 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
14628 Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
14629
14630 Redistribution and use in source and binary forms, with or without
14631 modification, are permitted provided that the following conditions
14632 are met:
14633
14634 * Redistributions of source code must retain the above
14635 copyright notice, this list of conditions and the following
14636 disclaimer.
14637
14638 * Redistributions in binary form must reproduce the above
14639 copyright notice, this list of conditions and the following
14640 disclaimer in the documentation and/or other materials
14641 provided with the distribution.
14642
14643 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
14644 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14645 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14646 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
14647 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
14648 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
14649 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
14650 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
14651 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
14652 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
14653 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14654 SUCH DAMAGE.
14655
14656 ***********************************************************************/
14657
14658/* -----[ Tokenizer (constants) ]----- */
14659
14660var KEYWORDS = array_to_hash([
14661 "break",
14662 "case",
14663 "catch",
14664 "const",
14665 "continue",
14666 "debugger",
14667 "default",
14668 "delete",
14669 "do",
14670 "else",
14671 "finally",
14672 "for",
14673 "function",
14674 "if",
14675 "in",
14676 "instanceof",
14677 "new",
14678 "return",
14679 "switch",
14680 "throw",
14681 "try",
14682 "typeof",
14683 "var",
14684 "void",
14685 "while",
14686 "with"
14687]);
14688
14689var RESERVED_WORDS = array_to_hash([
14690 "abstract",
14691 "boolean",
14692 "byte",
14693 "char",
14694 "class",
14695 "double",
14696 "enum",
14697 "export",
14698 "extends",
14699 "final",
14700 "float",
14701 "goto",
14702 "implements",
14703 "import",
14704 "int",
14705 "interface",
14706 "long",
14707 "native",
14708 "package",
14709 "private",
14710 "protected",
14711 "public",
14712 "short",
14713 "static",
14714 "super",
14715 "synchronized",
14716 "throws",
14717 "transient",
14718 "volatile"
14719]);
14720
14721var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
14722 "return",
14723 "new",
14724 "delete",
14725 "throw",
14726 "else",
14727 "case"
14728]);
14729
14730var KEYWORDS_ATOM = array_to_hash([
14731 "false",
14732 "null",
14733 "true",
14734 "undefined"
14735]);
14736
14737var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
14738
14739var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
14740var RE_OCT_NUMBER = /^0[0-7]+$/;
14741var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
14742
14743var OPERATORS = array_to_hash([
14744 "in",
14745 "instanceof",
14746 "typeof",
14747 "new",
14748 "void",
14749 "delete",
14750 "++",
14751 "--",
14752 "+",
14753 "-",
14754 "!",
14755 "~",
14756 "&",
14757 "|",
14758 "^",
14759 "*",
14760 "/",
14761 "%",
14762 ">>",
14763 "<<",
14764 ">>>",
14765 "<",
14766 ">",
14767 "<=",
14768 ">=",
14769 "==",
14770 "===",
14771 "!=",
14772 "!==",
14773 "?",
14774 "=",
14775 "+=",
14776 "-=",
14777 "/=",
14778 "*=",
14779 "%=",
14780 ">>=",
14781 "<<=",
14782 ">>>=",
14783 "|=",
14784 "^=",
14785 "&=",
14786 "&&",
14787 "||"
14788]);
14789
14790var 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"));
14791
14792var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:"));
14793
14794var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
14795
14796var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
14797
14798/* -----[ Tokenizer ]----- */
14799
14800var UNICODE = { // Unicode 6.1
14801 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]"),
14802 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]"),
14803 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]"),
14804 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]")
14805};
14806
14807function is_letter(ch) {
14808 return UNICODE.letter.test(ch);
14809};
14810
14811function is_digit(ch) {
14812 ch = ch.charCodeAt(0);
14813 return ch >= 48 && ch <= 57;
14814};
14815
14816function is_unicode_digit(ch) {
14817 return UNICODE.digit.test(ch);
14818}
14819
14820function is_alphanumeric_char(ch) {
14821 return is_digit(ch) || is_letter(ch);
14822};
14823
14824function is_unicode_combining_mark(ch) {
14825 return UNICODE.combining_mark.test(ch);
14826};
14827
14828function is_unicode_connector_punctuation(ch) {
14829 return UNICODE.connector_punctuation.test(ch);
14830};
14831
14832function is_identifier_start(ch) {
14833 return ch == "$" || ch == "_" || is_letter(ch);
14834};
14835
14836function is_identifier_char(ch) {
14837 return is_identifier_start(ch)
14838 || is_unicode_combining_mark(ch)
14839 || is_unicode_digit(ch)
14840 || is_unicode_connector_punctuation(ch)
14841 || ch == "\u200c" // zero-width non-joiner <ZWNJ>
14842 || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
14843 ;
14844};
14845
14846function parse_js_number(num) {
14847 if (RE_HEX_NUMBER.test(num)) {
14848 return parseInt(num.substr(2), 16);
14849 } else if (RE_OCT_NUMBER.test(num)) {
14850 return parseInt(num.substr(1), 8);
14851 } else if (RE_DEC_NUMBER.test(num)) {
14852 return parseFloat(num);
14853 }
14854};
14855
14856function JS_Parse_Error(message, line, col, pos) {
14857 this.message = message;
14858 this.line = line + 1;
14859 this.col = col + 1;
14860 this.pos = pos + 1;
14861 this.stack = new Error().stack;
14862};
14863
14864JS_Parse_Error.prototype.toString = function() {
14865 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
14866};
14867
14868function js_error(message, line, col, pos) {
14869 throw new JS_Parse_Error(message, line, col, pos);
14870};
14871
14872function is_token(token, type, val) {
14873 return token.type == type && (val == null || token.value == val);
14874};
14875
14876var EX_EOF = {};
14877
14878function tokenizer($TEXT) {
14879
14880 var S = {
14881 text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
14882 pos : 0,
14883 tokpos : 0,
14884 line : 0,
14885 tokline : 0,
14886 col : 0,
14887 tokcol : 0,
14888 newline_before : false,
14889 regex_allowed : false,
14890 comments_before : []
14891 };
14892
14893 function peek() { return S.text.charAt(S.pos); };
14894
14895 function next(signal_eof, in_string) {
14896 var ch = S.text.charAt(S.pos++);
14897 if (signal_eof && !ch)
14898 throw EX_EOF;
14899 if (ch == "\n") {
14900 S.newline_before = S.newline_before || !in_string;
14901 ++S.line;
14902 S.col = 0;
14903 } else {
14904 ++S.col;
14905 }
14906 return ch;
14907 };
14908
14909 function eof() {
14910 return !S.peek();
14911 };
14912
14913 function find(what, signal_eof) {
14914 var pos = S.text.indexOf(what, S.pos);
14915 if (signal_eof && pos == -1) throw EX_EOF;
14916 return pos;
14917 };
14918
14919 function start_token() {
14920 S.tokline = S.line;
14921 S.tokcol = S.col;
14922 S.tokpos = S.pos;
14923 };
14924
14925 function token(type, value, is_comment) {
14926 S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
14927 (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
14928 (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
14929 var ret = {
14930 type : type,
14931 value : value,
14932 line : S.tokline,
14933 col : S.tokcol,
14934 pos : S.tokpos,
14935 endpos : S.pos,
14936 nlb : S.newline_before
14937 };
14938 if (!is_comment) {
14939 ret.comments_before = S.comments_before;
14940 S.comments_before = [];
14941 // make note of any newlines in the comments that came before
14942 for (var i = 0, len = ret.comments_before.length; i < len; i++) {
14943 ret.nlb = ret.nlb || ret.comments_before[i].nlb;
14944 }
14945 }
14946 S.newline_before = false;
14947 return ret;
14948 };
14949
14950 function skip_whitespace() {
14951 while (HOP(WHITESPACE_CHARS, peek()))
14952 next();
14953 };
14954
14955 function read_while(pred) {
14956 var ret = "", ch = peek(), i = 0;
14957 while (ch && pred(ch, i++)) {
14958 ret += next();
14959 ch = peek();
14960 }
14961 return ret;
14962 };
14963
14964 function parse_error(err) {
14965 js_error(err, S.tokline, S.tokcol, S.tokpos);
14966 };
14967
14968 function read_num(prefix) {
14969 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
14970 var num = read_while(function(ch, i){
14971 if (ch == "x" || ch == "X") {
14972 if (has_x) return false;
14973 return has_x = true;
14974 }
14975 if (!has_x && (ch == "E" || ch == "e")) {
14976 if (has_e) return false;
14977 return has_e = after_e = true;
14978 }
14979 if (ch == "-") {
14980 if (after_e || (i == 0 && !prefix)) return true;
14981 return false;
14982 }
14983 if (ch == "+") return after_e;
14984 after_e = false;
14985 if (ch == ".") {
14986 if (!has_dot && !has_x && !has_e)
14987 return has_dot = true;
14988 return false;
14989 }
14990 return is_alphanumeric_char(ch);
14991 });
14992 if (prefix)
14993 num = prefix + num;
14994 var valid = parse_js_number(num);
14995 if (!isNaN(valid)) {
14996 return token("num", valid);
14997 } else {
14998 parse_error("Invalid syntax: " + num);
14999 }
15000 };
15001
15002 function read_escaped_char(in_string) {
15003 var ch = next(true, in_string);
15004 switch (ch) {
15005 case "n" : return "\n";
15006 case "r" : return "\r";
15007 case "t" : return "\t";
15008 case "b" : return "\b";
15009 case "v" : return "\u000b";
15010 case "f" : return "\f";
15011 case "0" : return "\0";
15012 case "x" : return String.fromCharCode(hex_bytes(2));
15013 case "u" : return String.fromCharCode(hex_bytes(4));
15014 case "\n": return "";
15015 default : return ch;
15016 }
15017 };
15018
15019 function hex_bytes(n) {
15020 var num = 0;
15021 for (; n > 0; --n) {
15022 var digit = parseInt(next(true), 16);
15023 if (isNaN(digit))
15024 parse_error("Invalid hex-character pattern in string");
15025 num = (num << 4) | digit;
15026 }
15027 return num;
15028 };
15029
15030 function read_string() {
15031 return with_eof_error("Unterminated string constant", function(){
15032 var quote = next(), ret = "";
15033 for (;;) {
15034 var ch = next(true);
15035 if (ch == "\\") {
15036 // read OctalEscapeSequence (XXX: deprecated if "strict mode")
15037 // https://github.com/mishoo/UglifyJS/issues/178
15038 var octal_len = 0, first = null;
15039 ch = read_while(function(ch){
15040 if (ch >= "0" && ch <= "7") {
15041 if (!first) {
15042 first = ch;
15043 return ++octal_len;
15044 }
15045 else if (first <= "3" && octal_len <= 2) return ++octal_len;
15046 else if (first >= "4" && octal_len <= 1) return ++octal_len;
15047 }
15048 return false;
15049 });
15050 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
15051 else ch = read_escaped_char(true);
15052 }
15053 else if (ch == quote) break;
15054 else if (ch == "\n") throw EX_EOF;
15055 ret += ch;
15056 }
15057 return token("string", ret);
15058 });
15059 };
15060
15061 function read_line_comment() {
15062 next();
15063 var i = find("\n"), ret;
15064 if (i == -1) {
15065 ret = S.text.substr(S.pos);
15066 S.pos = S.text.length;
15067 } else {
15068 ret = S.text.substring(S.pos, i);
15069 S.pos = i;
15070 }
15071 return token("comment1", ret, true);
15072 };
15073
15074 function read_multiline_comment() {
15075 next();
15076 return with_eof_error("Unterminated multiline comment", function(){
15077 var i = find("*/", true),
15078 text = S.text.substring(S.pos, i);
15079 S.pos = i + 2;
15080 S.line += text.split("\n").length - 1;
15081 S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
15082
15083 // https://github.com/mishoo/UglifyJS/issues/#issue/100
15084 if (/^@cc_on/i.test(text)) {
15085 warn("WARNING: at line " + S.line);
15086 warn("*** Found \"conditional comment\": " + text);
15087 warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer.");
15088 }
15089
15090 return token("comment2", text, true);
15091 });
15092 };
15093
15094 function read_name() {
15095 var backslash = false, name = "", ch, escaped = false, hex;
15096 while ((ch = peek()) != null) {
15097 if (!backslash) {
15098 if (ch == "\\") escaped = backslash = true, next();
15099 else if (is_identifier_char(ch)) name += next();
15100 else break;
15101 }
15102 else {
15103 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
15104 ch = read_escaped_char();
15105 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
15106 name += ch;
15107 backslash = false;
15108 }
15109 }
15110 if (HOP(KEYWORDS, name) && escaped) {
15111 hex = name.charCodeAt(0).toString(16).toUpperCase();
15112 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
15113 }
15114 return name;
15115 };
15116
15117 function read_regexp(regexp) {
15118 return with_eof_error("Unterminated regular expression", function(){
15119 var prev_backslash = false, ch, in_class = false;
15120 while ((ch = next(true))) if (prev_backslash) {
15121 regexp += "\\" + ch;
15122 prev_backslash = false;
15123 } else if (ch == "[") {
15124 in_class = true;
15125 regexp += ch;
15126 } else if (ch == "]" && in_class) {
15127 in_class = false;
15128 regexp += ch;
15129 } else if (ch == "/" && !in_class) {
15130 break;
15131 } else if (ch == "\\") {
15132 prev_backslash = true;
15133 } else {
15134 regexp += ch;
15135 }
15136 var mods = read_name();
15137 return token("regexp", [ regexp, mods ]);
15138 });
15139 };
15140
15141 function read_operator(prefix) {
15142 function grow(op) {
15143 if (!peek()) return op;
15144 var bigger = op + peek();
15145 if (HOP(OPERATORS, bigger)) {
15146 next();
15147 return grow(bigger);
15148 } else {
15149 return op;
15150 }
15151 };
15152 return token("operator", grow(prefix || next()));
15153 };
15154
15155 function handle_slash() {
15156 next();
15157 var regex_allowed = S.regex_allowed;
15158 switch (peek()) {
15159 case "/":
15160 S.comments_before.push(read_line_comment());
15161 S.regex_allowed = regex_allowed;
15162 return next_token();
15163 case "*":
15164 S.comments_before.push(read_multiline_comment());
15165 S.regex_allowed = regex_allowed;
15166 return next_token();
15167 }
15168 return S.regex_allowed ? read_regexp("") : read_operator("/");
15169 };
15170
15171 function handle_dot() {
15172 next();
15173 return is_digit(peek())
15174 ? read_num(".")
15175 : token("punc", ".");
15176 };
15177
15178 function read_word() {
15179 var word = read_name();
15180 return !HOP(KEYWORDS, word)
15181 ? token("name", word)
15182 : HOP(OPERATORS, word)
15183 ? token("operator", word)
15184 : HOP(KEYWORDS_ATOM, word)
15185 ? token("atom", word)
15186 : token("keyword", word);
15187 };
15188
15189 function with_eof_error(eof_error, cont) {
15190 try {
15191 return cont();
15192 } catch(ex) {
15193 if (ex === EX_EOF) parse_error(eof_error);
15194 else throw ex;
15195 }
15196 };
15197
15198 function next_token(force_regexp) {
15199 if (force_regexp != null)
15200 return read_regexp(force_regexp);
15201 skip_whitespace();
15202 start_token();
15203 var ch = peek();
15204 if (!ch) return token("eof");
15205 if (is_digit(ch)) return read_num();
15206 if (ch == '"' || ch == "'") return read_string();
15207 if (HOP(PUNC_CHARS, ch)) return token("punc", next());
15208 if (ch == ".") return handle_dot();
15209 if (ch == "/") return handle_slash();
15210 if (HOP(OPERATOR_CHARS, ch)) return read_operator();
15211 if (ch == "\\" || is_identifier_start(ch)) return read_word();
15212 parse_error("Unexpected character '" + ch + "'");
15213 };
15214
15215 next_token.context = function(nc) {
15216 if (nc) S = nc;
15217 return S;
15218 };
15219
15220 return next_token;
15221
15222};
15223
15224/* -----[ Parser (constants) ]----- */
15225
15226var UNARY_PREFIX = array_to_hash([
15227 "typeof",
15228 "void",
15229 "delete",
15230 "--",
15231 "++",
15232 "!",
15233 "~",
15234 "-",
15235 "+"
15236]);
15237
15238var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
15239
15240var ASSIGNMENT = (function(a, ret, i){
15241 while (i < a.length) {
15242 ret[a[i]] = a[i].substr(0, a[i].length - 1);
15243 i++;
15244 }
15245 return ret;
15246})(
15247 ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
15248 { "=": true },
15249 0
15250);
15251
15252var PRECEDENCE = (function(a, ret){
15253 for (var i = 0, n = 1; i < a.length; ++i, ++n) {
15254 var b = a[i];
15255 for (var j = 0; j < b.length; ++j) {
15256 ret[b[j]] = n;
15257 }
15258 }
15259 return ret;
15260})(
15261 [
15262 ["||"],
15263 ["&&"],
15264 ["|"],
15265 ["^"],
15266 ["&"],
15267 ["==", "===", "!=", "!=="],
15268 ["<", ">", "<=", ">=", "in", "instanceof"],
15269 [">>", "<<", ">>>"],
15270 ["+", "-"],
15271 ["*", "/", "%"]
15272 ],
15273 {}
15274);
15275
15276var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
15277
15278var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
15279
15280/* -----[ Parser ]----- */
15281
15282function NodeWithToken(str, start, end) {
15283 this.name = str;
15284 this.start = start;
15285 this.end = end;
15286};
15287
15288NodeWithToken.prototype.toString = function() { return this.name; };
15289
15290function parse($TEXT, exigent_mode, embed_tokens) {
15291
15292 var S = {
15293 input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
15294 token : null,
15295 prev : null,
15296 peeked : null,
15297 in_function : 0,
15298 in_directives : true,
15299 in_loop : 0,
15300 labels : []
15301 };
15302
15303 S.token = next();
15304
15305 function is(type, value) {
15306 return is_token(S.token, type, value);
15307 };
15308
15309 function peek() { return S.peeked || (S.peeked = S.input()); };
15310
15311 function next() {
15312 S.prev = S.token;
15313 if (S.peeked) {
15314 S.token = S.peeked;
15315 S.peeked = null;
15316 } else {
15317 S.token = S.input();
15318 }
15319 S.in_directives = S.in_directives && (
15320 S.token.type == "string" || is("punc", ";")
15321 );
15322 return S.token;
15323 };
15324
15325 function prev() {
15326 return S.prev;
15327 };
15328
15329 function croak(msg, line, col, pos) {
15330 var ctx = S.input.context();
15331 js_error(msg,
15332 line != null ? line : ctx.tokline,
15333 col != null ? col : ctx.tokcol,
15334 pos != null ? pos : ctx.tokpos);
15335 };
15336
15337 function token_error(token, msg) {
15338 croak(msg, token.line, token.col);
15339 };
15340
15341 function unexpected(token) {
15342 if (token == null)
15343 token = S.token;
15344 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
15345 };
15346
15347 function expect_token(type, val) {
15348 if (is(type, val)) {
15349 return next();
15350 }
15351 token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
15352 };
15353
15354 function expect(punc) { return expect_token("punc", punc); };
15355
15356 function can_insert_semicolon() {
15357 return !exigent_mode && (
15358 S.token.nlb || is("eof") || is("punc", "}")
15359 );
15360 };
15361
15362 function semicolon() {
15363 if (is("punc", ";")) next();
15364 else if (!can_insert_semicolon()) unexpected();
15365 };
15366
15367 function as() {
15368 return slice(arguments);
15369 };
15370
15371 function parenthesised() {
15372 expect("(");
15373 var ex = expression();
15374 expect(")");
15375 return ex;
15376 };
15377
15378 function add_tokens(str, start, end) {
15379 return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
15380 };
15381
15382 function maybe_embed_tokens(parser) {
15383 if (embed_tokens) return function() {
15384 var start = S.token;
15385 var ast = parser.apply(this, arguments);
15386 ast[0] = add_tokens(ast[0], start, prev());
15387 return ast;
15388 };
15389 else return parser;
15390 };
15391
15392 var statement = maybe_embed_tokens(function() {
15393 if (is("operator", "/") || is("operator", "/=")) {
15394 S.peeked = null;
15395 S.token = S.input(S.token.value.substr(1)); // force regexp
15396 }
15397 switch (S.token.type) {
15398 case "string":
15399 var dir = S.in_directives, stat = simple_statement();
15400 if (dir && stat[1][0] == "string" && !is("punc", ","))
15401 return as("directive", stat[1][1]);
15402 return stat;
15403 case "num":
15404 case "regexp":
15405 case "operator":
15406 case "atom":
15407 return simple_statement();
15408
15409 case "name":
15410 return is_token(peek(), "punc", ":")
15411 ? labeled_statement(prog1(S.token.value, next, next))
15412 : simple_statement();
15413
15414 case "punc":
15415 switch (S.token.value) {
15416 case "{":
15417 return as("block", block_());
15418 case "[":
15419 case "(":
15420 return simple_statement();
15421 case ";":
15422 next();
15423 return as("block");
15424 default:
15425 unexpected();
15426 }
15427
15428 case "keyword":
15429 switch (prog1(S.token.value, next)) {
15430 case "break":
15431 return break_cont("break");
15432
15433 case "continue":
15434 return break_cont("continue");
15435
15436 case "debugger":
15437 semicolon();
15438 return as("debugger");
15439
15440 case "do":
15441 return (function(body){
15442 expect_token("keyword", "while");
15443 return as("do", prog1(parenthesised, semicolon), body);
15444 })(in_loop(statement));
15445
15446 case "for":
15447 return for_();
15448
15449 case "function":
15450 return function_(true);
15451
15452 case "if":
15453 return if_();
15454
15455 case "return":
15456 if (S.in_function == 0)
15457 croak("'return' outside of function");
15458 return as("return",
15459 is("punc", ";")
15460 ? (next(), null)
15461 : can_insert_semicolon()
15462 ? null
15463 : prog1(expression, semicolon));
15464
15465 case "switch":
15466 return as("switch", parenthesised(), switch_block_());
15467
15468 case "throw":
15469 if (S.token.nlb)
15470 croak("Illegal newline after 'throw'");
15471 return as("throw", prog1(expression, semicolon));
15472
15473 case "try":
15474 return try_();
15475
15476 case "var":
15477 return prog1(var_, semicolon);
15478
15479 case "const":
15480 return prog1(const_, semicolon);
15481
15482 case "while":
15483 return as("while", parenthesised(), in_loop(statement));
15484
15485 case "with":
15486 return as("with", parenthesised(), statement());
15487
15488 default:
15489 unexpected();
15490 }
15491 }
15492 });
15493
15494 function labeled_statement(label) {
15495 S.labels.push(label);
15496 var start = S.token, stat = statement();
15497 if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
15498 unexpected(start);
15499 S.labels.pop();
15500 return as("label", label, stat);
15501 };
15502
15503 function simple_statement() {
15504 return as("stat", prog1(expression, semicolon));
15505 };
15506
15507 function break_cont(type) {
15508 var name;
15509 if (!can_insert_semicolon()) {
15510 name = is("name") ? S.token.value : null;
15511 }
15512 if (name != null) {
15513 next();
15514 if (!member(name, S.labels))
15515 croak("Label " + name + " without matching loop or statement");
15516 }
15517 else if (S.in_loop == 0)
15518 croak(type + " not inside a loop or switch");
15519 semicolon();
15520 return as(type, name);
15521 };
15522
15523 function for_() {
15524 expect("(");
15525 var init = null;
15526 if (!is("punc", ";")) {
15527 init = is("keyword", "var")
15528 ? (next(), var_(true))
15529 : expression(true, true);
15530 if (is("operator", "in")) {
15531 if (init[0] == "var" && init[1].length > 1)
15532 croak("Only one variable declaration allowed in for..in loop");
15533 return for_in(init);
15534 }
15535 }
15536 return regular_for(init);
15537 };
15538
15539 function regular_for(init) {
15540 expect(";");
15541 var test = is("punc", ";") ? null : expression();
15542 expect(";");
15543 var step = is("punc", ")") ? null : expression();
15544 expect(")");
15545 return as("for", init, test, step, in_loop(statement));
15546 };
15547
15548 function for_in(init) {
15549 var lhs = init[0] == "var" ? as("name", init[1][0]) : init;
15550 next();
15551 var obj = expression();
15552 expect(")");
15553 return as("for-in", init, lhs, obj, in_loop(statement));
15554 };
15555
15556 var function_ = function(in_statement) {
15557 var name = is("name") ? prog1(S.token.value, next) : null;
15558 if (in_statement && !name)
15559 unexpected();
15560 expect("(");
15561 return as(in_statement ? "defun" : "function",
15562 name,
15563 // arguments
15564 (function(first, a){
15565 while (!is("punc", ")")) {
15566 if (first) first = false; else expect(",");
15567 if (!is("name")) unexpected();
15568 a.push(S.token.value);
15569 next();
15570 }
15571 next();
15572 return a;
15573 })(true, []),
15574 // body
15575 (function(){
15576 ++S.in_function;
15577 var loop = S.in_loop;
15578 S.in_directives = true;
15579 S.in_loop = 0;
15580 var a = block_();
15581 --S.in_function;
15582 S.in_loop = loop;
15583 return a;
15584 })());
15585 };
15586
15587 function if_() {
15588 var cond = parenthesised(), body = statement(), belse;
15589 if (is("keyword", "else")) {
15590 next();
15591 belse = statement();
15592 }
15593 return as("if", cond, body, belse);
15594 };
15595
15596 function block_() {
15597 expect("{");
15598 var a = [];
15599 while (!is("punc", "}")) {
15600 if (is("eof")) unexpected();
15601 a.push(statement());
15602 }
15603 next();
15604 return a;
15605 };
15606
15607 var switch_block_ = curry(in_loop, function(){
15608 expect("{");
15609 var a = [], cur = null;
15610 while (!is("punc", "}")) {
15611 if (is("eof")) unexpected();
15612 if (is("keyword", "case")) {
15613 next();
15614 cur = [];
15615 a.push([ expression(), cur ]);
15616 expect(":");
15617 }
15618 else if (is("keyword", "default")) {
15619 next();
15620 expect(":");
15621 cur = [];
15622 a.push([ null, cur ]);
15623 }
15624 else {
15625 if (!cur) unexpected();
15626 cur.push(statement());
15627 }
15628 }
15629 next();
15630 return a;
15631 });
15632
15633 function try_() {
15634 var body = block_(), bcatch, bfinally;
15635 if (is("keyword", "catch")) {
15636 next();
15637 expect("(");
15638 if (!is("name"))
15639 croak("Name expected");
15640 var name = S.token.value;
15641 next();
15642 expect(")");
15643 bcatch = [ name, block_() ];
15644 }
15645 if (is("keyword", "finally")) {
15646 next();
15647 bfinally = block_();
15648 }
15649 if (!bcatch && !bfinally)
15650 croak("Missing catch/finally blocks");
15651 return as("try", body, bcatch, bfinally);
15652 };
15653
15654 function vardefs(no_in) {
15655 var a = [];
15656 for (;;) {
15657 if (!is("name"))
15658 unexpected();
15659 var name = S.token.value;
15660 next();
15661 if (is("operator", "=")) {
15662 next();
15663 a.push([ name, expression(false, no_in) ]);
15664 } else {
15665 a.push([ name ]);
15666 }
15667 if (!is("punc", ","))
15668 break;
15669 next();
15670 }
15671 return a;
15672 };
15673
15674 function var_(no_in) {
15675 return as("var", vardefs(no_in));
15676 };
15677
15678 function const_() {
15679 return as("const", vardefs());
15680 };
15681
15682 function new_() {
15683 var newexp = expr_atom(false), args;
15684 if (is("punc", "(")) {
15685 next();
15686 args = expr_list(")");
15687 } else {
15688 args = [];
15689 }
15690 return subscripts(as("new", newexp, args), true);
15691 };
15692
15693 var expr_atom = maybe_embed_tokens(function(allow_calls) {
15694 if (is("operator", "new")) {
15695 next();
15696 return new_();
15697 }
15698 if (is("punc")) {
15699 switch (S.token.value) {
15700 case "(":
15701 next();
15702 return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
15703 case "[":
15704 next();
15705 return subscripts(array_(), allow_calls);
15706 case "{":
15707 next();
15708 return subscripts(object_(), allow_calls);
15709 }
15710 unexpected();
15711 }
15712 if (is("keyword", "function")) {
15713 next();
15714 return subscripts(function_(false), allow_calls);
15715 }
15716 if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
15717 var atom = S.token.type == "regexp"
15718 ? as("regexp", S.token.value[0], S.token.value[1])
15719 : as(S.token.type, S.token.value);
15720 return subscripts(prog1(atom, next), allow_calls);
15721 }
15722 unexpected();
15723 });
15724
15725 function expr_list(closing, allow_trailing_comma, allow_empty) {
15726 var first = true, a = [];
15727 while (!is("punc", closing)) {
15728 if (first) first = false; else expect(",");
15729 if (allow_trailing_comma && is("punc", closing)) break;
15730 if (is("punc", ",") && allow_empty) {
15731 a.push([ "atom", "undefined" ]);
15732 } else {
15733 a.push(expression(false));
15734 }
15735 }
15736 next();
15737 return a;
15738 };
15739
15740 function array_() {
15741 return as("array", expr_list("]", !exigent_mode, true));
15742 };
15743
15744 function object_() {
15745 var first = true, a = [];
15746 while (!is("punc", "}")) {
15747 if (first) first = false; else expect(",");
15748 if (!exigent_mode && is("punc", "}"))
15749 // allow trailing comma
15750 break;
15751 var type = S.token.type;
15752 var name = as_property_name();
15753 if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
15754 a.push([ as_name(), function_(false), name ]);
15755 } else {
15756 expect(":");
15757 a.push([ name, expression(false) ]);
15758 }
15759 }
15760 next();
15761 return as("object", a);
15762 };
15763
15764 function as_property_name() {
15765 switch (S.token.type) {
15766 case "num":
15767 case "string":
15768 return prog1(S.token.value, next);
15769 }
15770 return as_name();
15771 };
15772
15773 function as_name() {
15774 switch (S.token.type) {
15775 case "name":
15776 case "operator":
15777 case "keyword":
15778 case "atom":
15779 return prog1(S.token.value, next);
15780 default:
15781 unexpected();
15782 }
15783 };
15784
15785 function subscripts(expr, allow_calls) {
15786 if (is("punc", ".")) {
15787 next();
15788 return subscripts(as("dot", expr, as_name()), allow_calls);
15789 }
15790 if (is("punc", "[")) {
15791 next();
15792 return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
15793 }
15794 if (allow_calls && is("punc", "(")) {
15795 next();
15796 return subscripts(as("call", expr, expr_list(")")), true);
15797 }
15798 return expr;
15799 };
15800
15801 function maybe_unary(allow_calls) {
15802 if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
15803 return make_unary("unary-prefix",
15804 prog1(S.token.value, next),
15805 maybe_unary(allow_calls));
15806 }
15807 var val = expr_atom(allow_calls);
15808 while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) {
15809 val = make_unary("unary-postfix", S.token.value, val);
15810 next();
15811 }
15812 return val;
15813 };
15814
15815 function make_unary(tag, op, expr) {
15816 if ((op == "++" || op == "--") && !is_assignable(expr))
15817 croak("Invalid use of " + op + " operator");
15818 return as(tag, op, expr);
15819 };
15820
15821 function expr_op(left, min_prec, no_in) {
15822 var op = is("operator") ? S.token.value : null;
15823 if (op && op == "in" && no_in) op = null;
15824 var prec = op != null ? PRECEDENCE[op] : null;
15825 if (prec != null && prec > min_prec) {
15826 next();
15827 var right = expr_op(maybe_unary(true), prec, no_in);
15828 return expr_op(as("binary", op, left, right), min_prec, no_in);
15829 }
15830 return left;
15831 };
15832
15833 function expr_ops(no_in) {
15834 return expr_op(maybe_unary(true), 0, no_in);
15835 };
15836
15837 function maybe_conditional(no_in) {
15838 var expr = expr_ops(no_in);
15839 if (is("operator", "?")) {
15840 next();
15841 var yes = expression(false);
15842 expect(":");
15843 return as("conditional", expr, yes, expression(false, no_in));
15844 }
15845 return expr;
15846 };
15847
15848 function is_assignable(expr) {
15849 if (!exigent_mode) return true;
15850 switch (expr[0]+"") {
15851 case "dot":
15852 case "sub":
15853 case "new":
15854 case "call":
15855 return true;
15856 case "name":
15857 return expr[1] != "this";
15858 }
15859 };
15860
15861 function maybe_assign(no_in) {
15862 var left = maybe_conditional(no_in), val = S.token.value;
15863 if (is("operator") && HOP(ASSIGNMENT, val)) {
15864 if (is_assignable(left)) {
15865 next();
15866 return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in));
15867 }
15868 croak("Invalid assignment");
15869 }
15870 return left;
15871 };
15872
15873 var expression = maybe_embed_tokens(function(commas, no_in) {
15874 if (arguments.length == 0)
15875 commas = true;
15876 var expr = maybe_assign(no_in);
15877 if (commas && is("punc", ",")) {
15878 next();
15879 return as("seq", expr, expression(true, no_in));
15880 }
15881 return expr;
15882 });
15883
15884 function in_loop(cont) {
15885 try {
15886 ++S.in_loop;
15887 return cont();
15888 } finally {
15889 --S.in_loop;
15890 }
15891 };
15892
15893 return as("toplevel", (function(a){
15894 while (!is("eof"))
15895 a.push(statement());
15896 return a;
15897 })([]));
15898
15899};
15900
15901/* -----[ Utilities ]----- */
15902
15903function curry(f) {
15904 var args = slice(arguments, 1);
15905 return function() { return f.apply(this, args.concat(slice(arguments))); };
15906};
15907
15908function prog1(ret) {
15909 if (ret instanceof Function)
15910 ret = ret();
15911 for (var i = 1, n = arguments.length; --n > 0; ++i)
15912 arguments[i]();
15913 return ret;
15914};
15915
15916function array_to_hash(a) {
15917 var ret = {};
15918 for (var i = 0; i < a.length; ++i)
15919 ret[a[i]] = true;
15920 return ret;
15921};
15922
15923function slice(a, start) {
15924 return Array.prototype.slice.call(a, start || 0);
15925};
15926
15927function characters(str) {
15928 return str.split("");
15929};
15930
15931function member(name, array) {
15932 for (var i = array.length; --i >= 0;)
15933 if (array[i] == name)
15934 return true;
15935 return false;
15936};
15937
15938function HOP(obj, prop) {
15939 return Object.prototype.hasOwnProperty.call(obj, prop);
15940};
15941
15942var warn = function() {};
15943
15944/* -----[ Exports ]----- */
15945
15946exports.tokenizer = tokenizer;
15947exports.parse = parse;
15948exports.slice = slice;
15949exports.curry = curry;
15950exports.member = member;
15951exports.array_to_hash = array_to_hash;
15952exports.PRECEDENCE = PRECEDENCE;
15953exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
15954exports.RESERVED_WORDS = RESERVED_WORDS;
15955exports.KEYWORDS = KEYWORDS;
15956exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
15957exports.OPERATORS = OPERATORS;
15958exports.is_alphanumeric_char = is_alphanumeric_char;
15959exports.is_identifier_start = is_identifier_start;
15960exports.is_identifier_char = is_identifier_char;
15961exports.set_logger = function(logger) {
15962 warn = logger;
15963};
15964
15965// Local variables:
15966// js-indent-level: 4
15967// End:
15968});define('uglifyjs/squeeze-more', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
15969var jsp = require("./parse-js"),
15970 pro = require("./process"),
15971 slice = jsp.slice,
15972 member = jsp.member,
15973 curry = jsp.curry,
15974 MAP = pro.MAP,
15975 PRECEDENCE = jsp.PRECEDENCE,
15976 OPERATORS = jsp.OPERATORS;
15977
15978function ast_squeeze_more(ast) {
15979 var w = pro.ast_walker(), walk = w.walk, scope;
15980 function with_scope(s, cont) {
15981 var save = scope, ret;
15982 scope = s;
15983 ret = cont();
15984 scope = save;
15985 return ret;
15986 };
15987 function _lambda(name, args, body) {
15988 return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
15989 };
15990 return w.with_walkers({
15991 "toplevel": function(body) {
15992 return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
15993 },
15994 "function": _lambda,
15995 "defun": _lambda,
15996 "new": function(ctor, args) {
15997 if (ctor[0] == "name") {
15998 if (ctor[1] == "Array" && !scope.has("Array")) {
15999 if (args.length != 1) {
16000 return [ "array", args ];
16001 } else {
16002 return walk([ "call", [ "name", "Array" ], args ]);
16003 }
16004 } else if (ctor[1] == "Object" && !scope.has("Object")) {
16005 if (!args.length) {
16006 return [ "object", [] ];
16007 } else {
16008 return walk([ "call", [ "name", "Object" ], args ]);
16009 }
16010 } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) {
16011 return walk([ "call", [ "name", ctor[1] ], args]);
16012 }
16013 }
16014 },
16015 "call": function(expr, args) {
16016 if (expr[0] == "dot" && expr[1][0] == "string" && args.length == 1
16017 && (args[0][1] > 0 && expr[2] == "substring" || expr[2] == "substr")) {
16018 return [ "call", [ "dot", expr[1], "slice"], args];
16019 }
16020 if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
16021 // foo.toString() ==> foo+""
16022 if (expr[1][0] == "string") return expr[1];
16023 return [ "binary", "+", expr[1], [ "string", "" ]];
16024 }
16025 if (expr[0] == "name") {
16026 if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
16027 return [ "array", args ];
16028 }
16029 if (expr[1] == "Object" && !args.length && !scope.has("Object")) {
16030 return [ "object", [] ];
16031 }
16032 if (expr[1] == "String" && !scope.has("String")) {
16033 return [ "binary", "+", args[0], [ "string", "" ]];
16034 }
16035 }
16036 }
16037 }, function() {
16038 return walk(pro.ast_add_scope(ast));
16039 });
16040};
16041
16042exports.ast_squeeze_more = ast_squeeze_more;
16043
16044// Local variables:
16045// js-indent-level: 4
16046// End:
16047});
16048define('uglifyjs/process', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
16049/***********************************************************************
16050
16051 A JavaScript tokenizer / parser / beautifier / compressor.
16052
16053 This version is suitable for Node.js. With minimal changes (the
16054 exports stuff) it should work on any JS platform.
16055
16056 This file implements some AST processors. They work on data built
16057 by parse-js.
16058
16059 Exported functions:
16060
16061 - ast_mangle(ast, options) -- mangles the variable/function names
16062 in the AST. Returns an AST.
16063
16064 - ast_squeeze(ast) -- employs various optimizations to make the
16065 final generated code even smaller. Returns an AST.
16066
16067 - gen_code(ast, options) -- generates JS code from the AST. Pass
16068 true (or an object, see the code for some options) as second
16069 argument to get "pretty" (indented) code.
16070
16071 -------------------------------- (C) ---------------------------------
16072
16073 Author: Mihai Bazon
16074 <mihai.bazon@gmail.com>
16075 http://mihai.bazon.net/blog
16076
16077 Distributed under the BSD license:
16078
16079 Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
16080
16081 Redistribution and use in source and binary forms, with or without
16082 modification, are permitted provided that the following conditions
16083 are met:
16084
16085 * Redistributions of source code must retain the above
16086 copyright notice, this list of conditions and the following
16087 disclaimer.
16088
16089 * Redistributions in binary form must reproduce the above
16090 copyright notice, this list of conditions and the following
16091 disclaimer in the documentation and/or other materials
16092 provided with the distribution.
16093
16094 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
16095 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16096 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16097 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
16098 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
16099 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16100 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
16101 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16102 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
16103 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
16104 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16105 SUCH DAMAGE.
16106
16107 ***********************************************************************/
16108
16109var jsp = require("./parse-js"),
16110 curry = jsp.curry,
16111 slice = jsp.slice,
16112 member = jsp.member,
16113 is_identifier_char = jsp.is_identifier_char,
16114 PRECEDENCE = jsp.PRECEDENCE,
16115 OPERATORS = jsp.OPERATORS;
16116
16117/* -----[ helper for AST traversal ]----- */
16118
16119function ast_walker() {
16120 function _vardefs(defs) {
16121 return [ this[0], MAP(defs, function(def){
16122 var a = [ def[0] ];
16123 if (def.length > 1)
16124 a[1] = walk(def[1]);
16125 return a;
16126 }) ];
16127 };
16128 function _block(statements) {
16129 var out = [ this[0] ];
16130 if (statements != null)
16131 out.push(MAP(statements, walk));
16132 return out;
16133 };
16134 var walkers = {
16135 "string": function(str) {
16136 return [ this[0], str ];
16137 },
16138 "num": function(num) {
16139 return [ this[0], num ];
16140 },
16141 "name": function(name) {
16142 return [ this[0], name ];
16143 },
16144 "toplevel": function(statements) {
16145 return [ this[0], MAP(statements, walk) ];
16146 },
16147 "block": _block,
16148 "splice": _block,
16149 "var": _vardefs,
16150 "const": _vardefs,
16151 "try": function(t, c, f) {
16152 return [
16153 this[0],
16154 MAP(t, walk),
16155 c != null ? [ c[0], MAP(c[1], walk) ] : null,
16156 f != null ? MAP(f, walk) : null
16157 ];
16158 },
16159 "throw": function(expr) {
16160 return [ this[0], walk(expr) ];
16161 },
16162 "new": function(ctor, args) {
16163 return [ this[0], walk(ctor), MAP(args, walk) ];
16164 },
16165 "switch": function(expr, body) {
16166 return [ this[0], walk(expr), MAP(body, function(branch){
16167 return [ branch[0] ? walk(branch[0]) : null,
16168 MAP(branch[1], walk) ];
16169 }) ];
16170 },
16171 "break": function(label) {
16172 return [ this[0], label ];
16173 },
16174 "continue": function(label) {
16175 return [ this[0], label ];
16176 },
16177 "conditional": function(cond, t, e) {
16178 return [ this[0], walk(cond), walk(t), walk(e) ];
16179 },
16180 "assign": function(op, lvalue, rvalue) {
16181 return [ this[0], op, walk(lvalue), walk(rvalue) ];
16182 },
16183 "dot": function(expr) {
16184 return [ this[0], walk(expr) ].concat(slice(arguments, 1));
16185 },
16186 "call": function(expr, args) {
16187 return [ this[0], walk(expr), MAP(args, walk) ];
16188 },
16189 "function": function(name, args, body) {
16190 return [ this[0], name, args.slice(), MAP(body, walk) ];
16191 },
16192 "debugger": function() {
16193 return [ this[0] ];
16194 },
16195 "defun": function(name, args, body) {
16196 return [ this[0], name, args.slice(), MAP(body, walk) ];
16197 },
16198 "if": function(conditional, t, e) {
16199 return [ this[0], walk(conditional), walk(t), walk(e) ];
16200 },
16201 "for": function(init, cond, step, block) {
16202 return [ this[0], walk(init), walk(cond), walk(step), walk(block) ];
16203 },
16204 "for-in": function(vvar, key, hash, block) {
16205 return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ];
16206 },
16207 "while": function(cond, block) {
16208 return [ this[0], walk(cond), walk(block) ];
16209 },
16210 "do": function(cond, block) {
16211 return [ this[0], walk(cond), walk(block) ];
16212 },
16213 "return": function(expr) {
16214 return [ this[0], walk(expr) ];
16215 },
16216 "binary": function(op, left, right) {
16217 return [ this[0], op, walk(left), walk(right) ];
16218 },
16219 "unary-prefix": function(op, expr) {
16220 return [ this[0], op, walk(expr) ];
16221 },
16222 "unary-postfix": function(op, expr) {
16223 return [ this[0], op, walk(expr) ];
16224 },
16225 "sub": function(expr, subscript) {
16226 return [ this[0], walk(expr), walk(subscript) ];
16227 },
16228 "object": function(props) {
16229 return [ this[0], MAP(props, function(p){
16230 return p.length == 2
16231 ? [ p[0], walk(p[1]) ]
16232 : [ p[0], walk(p[1]), p[2] ]; // get/set-ter
16233 }) ];
16234 },
16235 "regexp": function(rx, mods) {
16236 return [ this[0], rx, mods ];
16237 },
16238 "array": function(elements) {
16239 return [ this[0], MAP(elements, walk) ];
16240 },
16241 "stat": function(stat) {
16242 return [ this[0], walk(stat) ];
16243 },
16244 "seq": function() {
16245 return [ this[0] ].concat(MAP(slice(arguments), walk));
16246 },
16247 "label": function(name, block) {
16248 return [ this[0], name, walk(block) ];
16249 },
16250 "with": function(expr, block) {
16251 return [ this[0], walk(expr), walk(block) ];
16252 },
16253 "atom": function(name) {
16254 return [ this[0], name ];
16255 },
16256 "directive": function(dir) {
16257 return [ this[0], dir ];
16258 }
16259 };
16260
16261 var user = {};
16262 var stack = [];
16263 function walk(ast) {
16264 if (ast == null)
16265 return null;
16266 try {
16267 stack.push(ast);
16268 var type = ast[0];
16269 var gen = user[type];
16270 if (gen) {
16271 var ret = gen.apply(ast, ast.slice(1));
16272 if (ret != null)
16273 return ret;
16274 }
16275 gen = walkers[type];
16276 return gen.apply(ast, ast.slice(1));
16277 } finally {
16278 stack.pop();
16279 }
16280 };
16281
16282 function dive(ast) {
16283 if (ast == null)
16284 return null;
16285 try {
16286 stack.push(ast);
16287 return walkers[ast[0]].apply(ast, ast.slice(1));
16288 } finally {
16289 stack.pop();
16290 }
16291 };
16292
16293 function with_walkers(walkers, cont){
16294 var save = {}, i;
16295 for (i in walkers) if (HOP(walkers, i)) {
16296 save[i] = user[i];
16297 user[i] = walkers[i];
16298 }
16299 var ret = cont();
16300 for (i in save) if (HOP(save, i)) {
16301 if (!save[i]) delete user[i];
16302 else user[i] = save[i];
16303 }
16304 return ret;
16305 };
16306
16307 return {
16308 walk: walk,
16309 dive: dive,
16310 with_walkers: with_walkers,
16311 parent: function() {
16312 return stack[stack.length - 2]; // last one is current node
16313 },
16314 stack: function() {
16315 return stack;
16316 }
16317 };
16318};
16319
16320/* -----[ Scope and mangling ]----- */
16321
16322function Scope(parent) {
16323 this.names = {}; // names defined in this scope
16324 this.mangled = {}; // mangled names (orig.name => mangled)
16325 this.rev_mangled = {}; // reverse lookup (mangled => orig.name)
16326 this.cname = -1; // current mangled name
16327 this.refs = {}; // names referenced from this scope
16328 this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes
16329 this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes
16330 this.directives = []; // directives activated from this scope
16331 this.parent = parent; // parent scope
16332 this.children = []; // sub-scopes
16333 if (parent) {
16334 this.level = parent.level + 1;
16335 parent.children.push(this);
16336 } else {
16337 this.level = 0;
16338 }
16339};
16340
16341function base54_digits() {
16342 if (typeof DIGITS_OVERRIDE_FOR_TESTING != "undefined")
16343 return DIGITS_OVERRIDE_FOR_TESTING;
16344 else
16345 return "etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984";
16346}
16347
16348var base54 = (function(){
16349 var DIGITS = base54_digits();
16350 return function(num) {
16351 var ret = "", base = 54;
16352 do {
16353 ret += DIGITS.charAt(num % base);
16354 num = Math.floor(num / base);
16355 base = 64;
16356 } while (num > 0);
16357 return ret;
16358 };
16359})();
16360
16361Scope.prototype = {
16362 has: function(name) {
16363 for (var s = this; s; s = s.parent)
16364 if (HOP(s.names, name))
16365 return s;
16366 },
16367 has_mangled: function(mname) {
16368 for (var s = this; s; s = s.parent)
16369 if (HOP(s.rev_mangled, mname))
16370 return s;
16371 },
16372 toJSON: function() {
16373 return {
16374 names: this.names,
16375 uses_eval: this.uses_eval,
16376 uses_with: this.uses_with
16377 };
16378 },
16379
16380 next_mangled: function() {
16381 // we must be careful that the new mangled name:
16382 //
16383 // 1. doesn't shadow a mangled name from a parent
16384 // scope, unless we don't reference the original
16385 // name from this scope OR from any sub-scopes!
16386 // This will get slow.
16387 //
16388 // 2. doesn't shadow an original name from a parent
16389 // scope, in the event that the name is not mangled
16390 // in the parent scope and we reference that name
16391 // here OR IN ANY SUBSCOPES!
16392 //
16393 // 3. doesn't shadow a name that is referenced but not
16394 // defined (possibly global defined elsewhere).
16395 for (;;) {
16396 var m = base54(++this.cname), prior;
16397
16398 // case 1.
16399 prior = this.has_mangled(m);
16400 if (prior && this.refs[prior.rev_mangled[m]] === prior)
16401 continue;
16402
16403 // case 2.
16404 prior = this.has(m);
16405 if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m))
16406 continue;
16407
16408 // case 3.
16409 if (HOP(this.refs, m) && this.refs[m] == null)
16410 continue;
16411
16412 // I got "do" once. :-/
16413 if (!is_identifier(m))
16414 continue;
16415
16416 return m;
16417 }
16418 },
16419 set_mangle: function(name, m) {
16420 this.rev_mangled[m] = name;
16421 return this.mangled[name] = m;
16422 },
16423 get_mangled: function(name, newMangle) {
16424 if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use
16425 var s = this.has(name);
16426 if (!s) return name; // not in visible scope, no mangle
16427 if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope
16428 if (!newMangle) return name; // not found and no mangling requested
16429 return s.set_mangle(name, s.next_mangled());
16430 },
16431 references: function(name) {
16432 return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name];
16433 },
16434 define: function(name, type) {
16435 if (name != null) {
16436 if (type == "var" || !HOP(this.names, name))
16437 this.names[name] = type || "var";
16438 return name;
16439 }
16440 },
16441 active_directive: function(dir) {
16442 return member(dir, this.directives) || this.parent && this.parent.active_directive(dir);
16443 }
16444};
16445
16446function ast_add_scope(ast) {
16447
16448 var current_scope = null;
16449 var w = ast_walker(), walk = w.walk;
16450 var having_eval = [];
16451
16452 function with_new_scope(cont) {
16453 current_scope = new Scope(current_scope);
16454 current_scope.labels = new Scope();
16455 var ret = current_scope.body = cont();
16456 ret.scope = current_scope;
16457 current_scope = current_scope.parent;
16458 return ret;
16459 };
16460
16461 function define(name, type) {
16462 return current_scope.define(name, type);
16463 };
16464
16465 function reference(name) {
16466 current_scope.refs[name] = true;
16467 };
16468
16469 function _lambda(name, args, body) {
16470 var is_defun = this[0] == "defun";
16471 return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){
16472 if (!is_defun) define(name, "lambda");
16473 MAP(args, function(name){ define(name, "arg") });
16474 return MAP(body, walk);
16475 })];
16476 };
16477
16478 function _vardefs(type) {
16479 return function(defs) {
16480 MAP(defs, function(d){
16481 define(d[0], type);
16482 if (d[1]) reference(d[0]);
16483 });
16484 };
16485 };
16486
16487 function _breacont(label) {
16488 if (label)
16489 current_scope.labels.refs[label] = true;
16490 };
16491
16492 return with_new_scope(function(){
16493 // process AST
16494 var ret = w.with_walkers({
16495 "function": _lambda,
16496 "defun": _lambda,
16497 "label": function(name, stat) { current_scope.labels.define(name) },
16498 "break": _breacont,
16499 "continue": _breacont,
16500 "with": function(expr, block) {
16501 for (var s = current_scope; s; s = s.parent)
16502 s.uses_with = true;
16503 },
16504 "var": _vardefs("var"),
16505 "const": _vardefs("const"),
16506 "try": function(t, c, f) {
16507 if (c != null) return [
16508 this[0],
16509 MAP(t, walk),
16510 [ define(c[0], "catch"), MAP(c[1], walk) ],
16511 f != null ? MAP(f, walk) : null
16512 ];
16513 },
16514 "name": function(name) {
16515 if (name == "eval")
16516 having_eval.push(current_scope);
16517 reference(name);
16518 }
16519 }, function(){
16520 return walk(ast);
16521 });
16522
16523 // the reason why we need an additional pass here is
16524 // that names can be used prior to their definition.
16525
16526 // scopes where eval was detected and their parents
16527 // are marked with uses_eval, unless they define the
16528 // "eval" name.
16529 MAP(having_eval, function(scope){
16530 if (!scope.has("eval")) while (scope) {
16531 scope.uses_eval = true;
16532 scope = scope.parent;
16533 }
16534 });
16535
16536 // for referenced names it might be useful to know
16537 // their origin scope. current_scope here is the
16538 // toplevel one.
16539 function fixrefs(scope, i) {
16540 // do children first; order shouldn't matter
16541 for (i = scope.children.length; --i >= 0;)
16542 fixrefs(scope.children[i]);
16543 for (i in scope.refs) if (HOP(scope.refs, i)) {
16544 // find origin scope and propagate the reference to origin
16545 for (var origin = scope.has(i), s = scope; s; s = s.parent) {
16546 s.refs[i] = origin;
16547 if (s === origin) break;
16548 }
16549 }
16550 };
16551 fixrefs(current_scope);
16552
16553 return ret;
16554 });
16555
16556};
16557
16558/* -----[ mangle names ]----- */
16559
16560function ast_mangle(ast, options) {
16561 var w = ast_walker(), walk = w.walk, scope;
16562 options = defaults(options, {
16563 mangle : true,
16564 toplevel : false,
16565 defines : null,
16566 except : null,
16567 no_functions : false
16568 });
16569
16570 function get_mangled(name, newMangle) {
16571 if (!options.mangle) return name;
16572 if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel
16573 if (options.except && member(name, options.except))
16574 return name;
16575 if (options.no_functions && HOP(scope.names, name) &&
16576 (scope.names[name] == 'defun' || scope.names[name] == 'lambda'))
16577 return name;
16578 return scope.get_mangled(name, newMangle);
16579 };
16580
16581 function get_define(name) {
16582 if (options.defines) {
16583 // we always lookup a defined symbol for the current scope FIRST, so declared
16584 // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value
16585 if (!scope.has(name)) {
16586 if (HOP(options.defines, name)) {
16587 return options.defines[name];
16588 }
16589 }
16590 return null;
16591 }
16592 };
16593
16594 function _lambda(name, args, body) {
16595 if (!options.no_functions && options.mangle) {
16596 var is_defun = this[0] == "defun", extra;
16597 if (name) {
16598 if (is_defun) name = get_mangled(name);
16599 else if (body.scope.references(name)) {
16600 extra = {};
16601 if (!(scope.uses_eval || scope.uses_with))
16602 name = extra[name] = scope.next_mangled();
16603 else
16604 extra[name] = name;
16605 }
16606 else name = null;
16607 }
16608 }
16609 body = with_scope(body.scope, function(){
16610 args = MAP(args, function(name){ return get_mangled(name) });
16611 return MAP(body, walk);
16612 }, extra);
16613 return [ this[0], name, args, body ];
16614 };
16615
16616 function with_scope(s, cont, extra) {
16617 var _scope = scope;
16618 scope = s;
16619 if (extra) for (var i in extra) if (HOP(extra, i)) {
16620 s.set_mangle(i, extra[i]);
16621 }
16622 for (var i in s.names) if (HOP(s.names, i)) {
16623 get_mangled(i, true);
16624 }
16625 var ret = cont();
16626 ret.scope = s;
16627 scope = _scope;
16628 return ret;
16629 };
16630
16631 function _vardefs(defs) {
16632 return [ this[0], MAP(defs, function(d){
16633 return [ get_mangled(d[0]), walk(d[1]) ];
16634 }) ];
16635 };
16636
16637 function _breacont(label) {
16638 if (label) return [ this[0], scope.labels.get_mangled(label) ];
16639 };
16640
16641 return w.with_walkers({
16642 "function": _lambda,
16643 "defun": function() {
16644 // move function declarations to the top when
16645 // they are not in some block.
16646 var ast = _lambda.apply(this, arguments);
16647 switch (w.parent()[0]) {
16648 case "toplevel":
16649 case "function":
16650 case "defun":
16651 return MAP.at_top(ast);
16652 }
16653 return ast;
16654 },
16655 "label": function(label, stat) {
16656 if (scope.labels.refs[label]) return [
16657 this[0],
16658 scope.labels.get_mangled(label, true),
16659 walk(stat)
16660 ];
16661 return walk(stat);
16662 },
16663 "break": _breacont,
16664 "continue": _breacont,
16665 "var": _vardefs,
16666 "const": _vardefs,
16667 "name": function(name) {
16668 return get_define(name) || [ this[0], get_mangled(name) ];
16669 },
16670 "try": function(t, c, f) {
16671 return [ this[0],
16672 MAP(t, walk),
16673 c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null,
16674 f != null ? MAP(f, walk) : null ];
16675 },
16676 "toplevel": function(body) {
16677 var self = this;
16678 return with_scope(self.scope, function(){
16679 return [ self[0], MAP(body, walk) ];
16680 });
16681 },
16682 "directive": function() {
16683 return MAP.at_top(this);
16684 }
16685 }, function() {
16686 return walk(ast_add_scope(ast));
16687 });
16688};
16689
16690/* -----[
16691 - compress foo["bar"] into foo.bar,
16692 - remove block brackets {} where possible
16693 - join consecutive var declarations
16694 - various optimizations for IFs:
16695 - if (cond) foo(); else bar(); ==> cond?foo():bar();
16696 - if (cond) foo(); ==> cond&&foo();
16697 - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); // also for throw
16698 - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
16699 ]----- */
16700
16701var warn = function(){};
16702
16703function best_of(ast1, ast2) {
16704 return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1;
16705};
16706
16707function last_stat(b) {
16708 if (b[0] == "block" && b[1] && b[1].length > 0)
16709 return b[1][b[1].length - 1];
16710 return b;
16711}
16712
16713function aborts(t) {
16714 if (t) switch (last_stat(t)[0]) {
16715 case "return":
16716 case "break":
16717 case "continue":
16718 case "throw":
16719 return true;
16720 }
16721};
16722
16723function boolean_expr(expr) {
16724 return ( (expr[0] == "unary-prefix"
16725 && member(expr[1], [ "!", "delete" ])) ||
16726
16727 (expr[0] == "binary"
16728 && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) ||
16729
16730 (expr[0] == "binary"
16731 && member(expr[1], [ "&&", "||" ])
16732 && boolean_expr(expr[2])
16733 && boolean_expr(expr[3])) ||
16734
16735 (expr[0] == "conditional"
16736 && boolean_expr(expr[2])
16737 && boolean_expr(expr[3])) ||
16738
16739 (expr[0] == "assign"
16740 && expr[1] === true
16741 && boolean_expr(expr[3])) ||
16742
16743 (expr[0] == "seq"
16744 && boolean_expr(expr[expr.length - 1]))
16745 );
16746};
16747
16748function empty(b) {
16749 return !b || (b[0] == "block" && (!b[1] || b[1].length == 0));
16750};
16751
16752function is_string(node) {
16753 return (node[0] == "string" ||
16754 node[0] == "unary-prefix" && node[1] == "typeof" ||
16755 node[0] == "binary" && node[1] == "+" &&
16756 (is_string(node[2]) || is_string(node[3])));
16757};
16758
16759var when_constant = (function(){
16760
16761 var $NOT_CONSTANT = {};
16762
16763 // this can only evaluate constant expressions. If it finds anything
16764 // not constant, it throws $NOT_CONSTANT.
16765 function evaluate(expr) {
16766 switch (expr[0]) {
16767 case "string":
16768 case "num":
16769 return expr[1];
16770 case "name":
16771 case "atom":
16772 switch (expr[1]) {
16773 case "true": return true;
16774 case "false": return false;
16775 case "null": return null;
16776 }
16777 break;
16778 case "unary-prefix":
16779 switch (expr[1]) {
16780 case "!": return !evaluate(expr[2]);
16781 case "typeof": return typeof evaluate(expr[2]);
16782 case "~": return ~evaluate(expr[2]);
16783 case "-": return -evaluate(expr[2]);
16784 case "+": return +evaluate(expr[2]);
16785 }
16786 break;
16787 case "binary":
16788 var left = expr[2], right = expr[3];
16789 switch (expr[1]) {
16790 case "&&" : return evaluate(left) && evaluate(right);
16791 case "||" : return evaluate(left) || evaluate(right);
16792 case "|" : return evaluate(left) | evaluate(right);
16793 case "&" : return evaluate(left) & evaluate(right);
16794 case "^" : return evaluate(left) ^ evaluate(right);
16795 case "+" : return evaluate(left) + evaluate(right);
16796 case "*" : return evaluate(left) * evaluate(right);
16797 case "/" : return evaluate(left) / evaluate(right);
16798 case "%" : return evaluate(left) % evaluate(right);
16799 case "-" : return evaluate(left) - evaluate(right);
16800 case "<<" : return evaluate(left) << evaluate(right);
16801 case ">>" : return evaluate(left) >> evaluate(right);
16802 case ">>>" : return evaluate(left) >>> evaluate(right);
16803 case "==" : return evaluate(left) == evaluate(right);
16804 case "===" : return evaluate(left) === evaluate(right);
16805 case "!=" : return evaluate(left) != evaluate(right);
16806 case "!==" : return evaluate(left) !== evaluate(right);
16807 case "<" : return evaluate(left) < evaluate(right);
16808 case "<=" : return evaluate(left) <= evaluate(right);
16809 case ">" : return evaluate(left) > evaluate(right);
16810 case ">=" : return evaluate(left) >= evaluate(right);
16811 case "in" : return evaluate(left) in evaluate(right);
16812 case "instanceof" : return evaluate(left) instanceof evaluate(right);
16813 }
16814 }
16815 throw $NOT_CONSTANT;
16816 };
16817
16818 return function(expr, yes, no) {
16819 try {
16820 var val = evaluate(expr), ast;
16821 switch (typeof val) {
16822 case "string": ast = [ "string", val ]; break;
16823 case "number": ast = [ "num", val ]; break;
16824 case "boolean": ast = [ "name", String(val) ]; break;
16825 default:
16826 if (val === null) { ast = [ "atom", "null" ]; break; }
16827 throw new Error("Can't handle constant of type: " + (typeof val));
16828 }
16829 return yes.call(expr, ast, val);
16830 } catch(ex) {
16831 if (ex === $NOT_CONSTANT) {
16832 if (expr[0] == "binary"
16833 && (expr[1] == "===" || expr[1] == "!==")
16834 && ((is_string(expr[2]) && is_string(expr[3]))
16835 || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) {
16836 expr[1] = expr[1].substr(0, 2);
16837 }
16838 else if (no && expr[0] == "binary"
16839 && (expr[1] == "||" || expr[1] == "&&")) {
16840 // the whole expression is not constant but the lval may be...
16841 try {
16842 var lval = evaluate(expr[2]);
16843 expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) ||
16844 (expr[1] == "||" && (lval ? lval : expr[3])) ||
16845 expr);
16846 } catch(ex2) {
16847 // IGNORE... lval is not constant
16848 }
16849 }
16850 return no ? no.call(expr, expr) : null;
16851 }
16852 else throw ex;
16853 }
16854 };
16855
16856})();
16857
16858function warn_unreachable(ast) {
16859 if (!empty(ast))
16860 warn("Dropping unreachable code: " + gen_code(ast, true));
16861};
16862
16863function prepare_ifs(ast) {
16864 var w = ast_walker(), walk = w.walk;
16865 // In this first pass, we rewrite ifs which abort with no else with an
16866 // if-else. For example:
16867 //
16868 // if (x) {
16869 // blah();
16870 // return y;
16871 // }
16872 // foobar();
16873 //
16874 // is rewritten into:
16875 //
16876 // if (x) {
16877 // blah();
16878 // return y;
16879 // } else {
16880 // foobar();
16881 // }
16882 function redo_if(statements) {
16883 statements = MAP(statements, walk);
16884
16885 for (var i = 0; i < statements.length; ++i) {
16886 var fi = statements[i];
16887 if (fi[0] != "if") continue;
16888
16889 if (fi[3]) continue;
16890
16891 var t = fi[2];
16892 if (!aborts(t)) continue;
16893
16894 var conditional = walk(fi[1]);
16895
16896 var e_body = redo_if(statements.slice(i + 1));
16897 var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ];
16898
16899 return statements.slice(0, i).concat([ [
16900 fi[0], // "if"
16901 conditional, // conditional
16902 t, // then
16903 e // else
16904 ] ]);
16905 }
16906
16907 return statements;
16908 };
16909
16910 function redo_if_lambda(name, args, body) {
16911 body = redo_if(body);
16912 return [ this[0], name, args, body ];
16913 };
16914
16915 function redo_if_block(statements) {
16916 return [ this[0], statements != null ? redo_if(statements) : null ];
16917 };
16918
16919 return w.with_walkers({
16920 "defun": redo_if_lambda,
16921 "function": redo_if_lambda,
16922 "block": redo_if_block,
16923 "splice": redo_if_block,
16924 "toplevel": function(statements) {
16925 return [ this[0], redo_if(statements) ];
16926 },
16927 "try": function(t, c, f) {
16928 return [
16929 this[0],
16930 redo_if(t),
16931 c != null ? [ c[0], redo_if(c[1]) ] : null,
16932 f != null ? redo_if(f) : null
16933 ];
16934 }
16935 }, function() {
16936 return walk(ast);
16937 });
16938};
16939
16940function for_side_effects(ast, handler) {
16941 var w = ast_walker(), walk = w.walk;
16942 var $stop = {}, $restart = {};
16943 function stop() { throw $stop };
16944 function restart() { throw $restart };
16945 function found(){ return handler.call(this, this, w, stop, restart) };
16946 function unary(op) {
16947 if (op == "++" || op == "--")
16948 return found.apply(this, arguments);
16949 };
16950 function binary(op) {
16951 if (op == "&&" || op == "||")
16952 return found.apply(this, arguments);
16953 };
16954 return w.with_walkers({
16955 "try": found,
16956 "throw": found,
16957 "return": found,
16958 "new": found,
16959 "switch": found,
16960 "break": found,
16961 "continue": found,
16962 "assign": found,
16963 "call": found,
16964 "if": found,
16965 "for": found,
16966 "for-in": found,
16967 "while": found,
16968 "do": found,
16969 "return": found,
16970 "unary-prefix": unary,
16971 "unary-postfix": unary,
16972 "conditional": found,
16973 "binary": binary,
16974 "defun": found
16975 }, function(){
16976 while (true) try {
16977 walk(ast);
16978 break;
16979 } catch(ex) {
16980 if (ex === $stop) break;
16981 if (ex === $restart) continue;
16982 throw ex;
16983 }
16984 });
16985};
16986
16987function ast_lift_variables(ast) {
16988 var w = ast_walker(), walk = w.walk, scope;
16989 function do_body(body, env) {
16990 var _scope = scope;
16991 scope = env;
16992 body = MAP(body, walk);
16993 var hash = {}, names = MAP(env.names, function(type, name){
16994 if (type != "var") return MAP.skip;
16995 if (!env.references(name)) return MAP.skip;
16996 hash[name] = true;
16997 return [ name ];
16998 });
16999 if (names.length > 0) {
17000 // looking for assignments to any of these variables.
17001 // we can save considerable space by moving the definitions
17002 // in the var declaration.
17003 for_side_effects([ "block", body ], function(ast, walker, stop, restart) {
17004 if (ast[0] == "assign"
17005 && ast[1] === true
17006 && ast[2][0] == "name"
17007 && HOP(hash, ast[2][1])) {
17008 // insert the definition into the var declaration
17009 for (var i = names.length; --i >= 0;) {
17010 if (names[i][0] == ast[2][1]) {
17011 if (names[i][1]) // this name already defined, we must stop
17012 stop();
17013 names[i][1] = ast[3]; // definition
17014 names.push(names.splice(i, 1)[0]);
17015 break;
17016 }
17017 }
17018 // remove this assignment from the AST.
17019 var p = walker.parent();
17020 if (p[0] == "seq") {
17021 var a = p[2];
17022 a.unshift(0, p.length);
17023 p.splice.apply(p, a);
17024 }
17025 else if (p[0] == "stat") {
17026 p.splice(0, p.length, "block"); // empty statement
17027 }
17028 else {
17029 stop();
17030 }
17031 restart();
17032 }
17033 stop();
17034 });
17035 body.unshift([ "var", names ]);
17036 }
17037 scope = _scope;
17038 return body;
17039 };
17040 function _vardefs(defs) {
17041 var ret = null;
17042 for (var i = defs.length; --i >= 0;) {
17043 var d = defs[i];
17044 if (!d[1]) continue;
17045 d = [ "assign", true, [ "name", d[0] ], d[1] ];
17046 if (ret == null) ret = d;
17047 else ret = [ "seq", d, ret ];
17048 }
17049 if (ret == null && w.parent()[0] != "for") {
17050 if (w.parent()[0] == "for-in")
17051 return [ "name", defs[0][0] ];
17052 return MAP.skip;
17053 }
17054 return [ "stat", ret ];
17055 };
17056 function _toplevel(body) {
17057 return [ this[0], do_body(body, this.scope) ];
17058 };
17059 return w.with_walkers({
17060 "function": function(name, args, body){
17061 for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
17062 args.pop();
17063 if (!body.scope.references(name)) name = null;
17064 return [ this[0], name, args, do_body(body, body.scope) ];
17065 },
17066 "defun": function(name, args, body){
17067 if (!scope.references(name)) return MAP.skip;
17068 for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);)
17069 args.pop();
17070 return [ this[0], name, args, do_body(body, body.scope) ];
17071 },
17072 "var": _vardefs,
17073 "toplevel": _toplevel
17074 }, function(){
17075 return walk(ast_add_scope(ast));
17076 });
17077};
17078
17079function ast_squeeze(ast, options) {
17080 ast = squeeze_1(ast, options);
17081 ast = squeeze_2(ast, options);
17082 return ast;
17083};
17084
17085function squeeze_1(ast, options) {
17086 options = defaults(options, {
17087 make_seqs : true,
17088 dead_code : true,
17089 no_warnings : false,
17090 keep_comps : true,
17091 unsafe : false
17092 });
17093
17094 var w = ast_walker(), walk = w.walk, scope;
17095
17096 function negate(c) {
17097 var not_c = [ "unary-prefix", "!", c ];
17098 switch (c[0]) {
17099 case "unary-prefix":
17100 return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c;
17101 case "seq":
17102 c = slice(c);
17103 c[c.length - 1] = negate(c[c.length - 1]);
17104 return c;
17105 case "conditional":
17106 return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]);
17107 case "binary":
17108 var op = c[1], left = c[2], right = c[3];
17109 if (!options.keep_comps) switch (op) {
17110 case "<=" : return [ "binary", ">", left, right ];
17111 case "<" : return [ "binary", ">=", left, right ];
17112 case ">=" : return [ "binary", "<", left, right ];
17113 case ">" : return [ "binary", "<=", left, right ];
17114 }
17115 switch (op) {
17116 case "==" : return [ "binary", "!=", left, right ];
17117 case "!=" : return [ "binary", "==", left, right ];
17118 case "===" : return [ "binary", "!==", left, right ];
17119 case "!==" : return [ "binary", "===", left, right ];
17120 case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]);
17121 case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]);
17122 }
17123 break;
17124 }
17125 return not_c;
17126 };
17127
17128 function make_conditional(c, t, e) {
17129 var make_real_conditional = function() {
17130 if (c[0] == "unary-prefix" && c[1] == "!") {
17131 return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ];
17132 } else {
17133 return e ? best_of(
17134 [ "conditional", c, t, e ],
17135 [ "conditional", negate(c), e, t ]
17136 ) : [ "binary", "&&", c, t ];
17137 }
17138 };
17139 // shortcut the conditional if the expression has a constant value
17140 return when_constant(c, function(ast, val){
17141 warn_unreachable(val ? e : t);
17142 return (val ? t : e);
17143 }, make_real_conditional);
17144 };
17145
17146 function rmblock(block) {
17147 if (block != null && block[0] == "block" && block[1]) {
17148 if (block[1].length == 1)
17149 block = block[1][0];
17150 else if (block[1].length == 0)
17151 block = [ "block" ];
17152 }
17153 return block;
17154 };
17155
17156 function _lambda(name, args, body) {
17157 return [ this[0], name, args, tighten(body, "lambda") ];
17158 };
17159
17160 // this function does a few things:
17161 // 1. discard useless blocks
17162 // 2. join consecutive var declarations
17163 // 3. remove obviously dead code
17164 // 4. transform consecutive statements using the comma operator
17165 // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... }
17166 function tighten(statements, block_type) {
17167 statements = MAP(statements, walk);
17168
17169 statements = statements.reduce(function(a, stat){
17170 if (stat[0] == "block") {
17171 if (stat[1]) {
17172 a.push.apply(a, stat[1]);
17173 }
17174 } else {
17175 a.push(stat);
17176 }
17177 return a;
17178 }, []);
17179
17180 statements = (function(a, prev){
17181 statements.forEach(function(cur){
17182 if (prev && ((cur[0] == "var" && prev[0] == "var") ||
17183 (cur[0] == "const" && prev[0] == "const"))) {
17184 prev[1] = prev[1].concat(cur[1]);
17185 } else {
17186 a.push(cur);
17187 prev = cur;
17188 }
17189 });
17190 return a;
17191 })([]);
17192
17193 if (options.dead_code) statements = (function(a, has_quit){
17194 statements.forEach(function(st){
17195 if (has_quit) {
17196 if (st[0] == "function" || st[0] == "defun") {
17197 a.push(st);
17198 }
17199 else if (st[0] == "var" || st[0] == "const") {
17200 if (!options.no_warnings)
17201 warn("Variables declared in unreachable code");
17202 st[1] = MAP(st[1], function(def){
17203 if (def[1] && !options.no_warnings)
17204 warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]);
17205 return [ def[0] ];
17206 });
17207 a.push(st);
17208 }
17209 else if (!options.no_warnings)
17210 warn_unreachable(st);
17211 }
17212 else {
17213 a.push(st);
17214 if (member(st[0], [ "return", "throw", "break", "continue" ]))
17215 has_quit = true;
17216 }
17217 });
17218 return a;
17219 })([]);
17220
17221 if (options.make_seqs) statements = (function(a, prev) {
17222 statements.forEach(function(cur){
17223 if (prev && prev[0] == "stat" && cur[0] == "stat") {
17224 prev[1] = [ "seq", prev[1], cur[1] ];
17225 } else {
17226 a.push(cur);
17227 prev = cur;
17228 }
17229 });
17230 if (a.length >= 2
17231 && a[a.length-2][0] == "stat"
17232 && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw")
17233 && a[a.length-1][1])
17234 {
17235 a.splice(a.length - 2, 2,
17236 [ a[a.length-1][0],
17237 [ "seq", a[a.length-2][1], a[a.length-1][1] ]]);
17238 }
17239 return a;
17240 })([]);
17241
17242 // this increases jQuery by 1K. Probably not such a good idea after all..
17243 // part of this is done in prepare_ifs anyway.
17244 // if (block_type == "lambda") statements = (function(i, a, stat){
17245 // while (i < statements.length) {
17246 // stat = statements[i++];
17247 // if (stat[0] == "if" && !stat[3]) {
17248 // if (stat[2][0] == "return" && stat[2][1] == null) {
17249 // a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ]));
17250 // break;
17251 // }
17252 // var last = last_stat(stat[2]);
17253 // if (last[0] == "return" && last[1] == null) {
17254 // a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ]));
17255 // break;
17256 // }
17257 // }
17258 // a.push(stat);
17259 // }
17260 // return a;
17261 // })(0, []);
17262
17263 return statements;
17264 };
17265
17266 function make_if(c, t, e) {
17267 return when_constant(c, function(ast, val){
17268 if (val) {
17269 t = walk(t);
17270 warn_unreachable(e);
17271 return t || [ "block" ];
17272 } else {
17273 e = walk(e);
17274 warn_unreachable(t);
17275 return e || [ "block" ];
17276 }
17277 }, function() {
17278 return make_real_if(c, t, e);
17279 });
17280 };
17281
17282 function abort_else(c, t, e) {
17283 var ret = [ [ "if", negate(c), e ] ];
17284 if (t[0] == "block") {
17285 if (t[1]) ret = ret.concat(t[1]);
17286 } else {
17287 ret.push(t);
17288 }
17289 return walk([ "block", ret ]);
17290 };
17291
17292 function make_real_if(c, t, e) {
17293 c = walk(c);
17294 t = walk(t);
17295 e = walk(e);
17296
17297 if (empty(e) && empty(t))
17298 return [ "stat", c ];
17299
17300 if (empty(t)) {
17301 c = negate(c);
17302 t = e;
17303 e = null;
17304 } else if (empty(e)) {
17305 e = null;
17306 } else {
17307 // if we have both else and then, maybe it makes sense to switch them?
17308 (function(){
17309 var a = gen_code(c);
17310 var n = negate(c);
17311 var b = gen_code(n);
17312 if (b.length < a.length) {
17313 var tmp = t;
17314 t = e;
17315 e = tmp;
17316 c = n;
17317 }
17318 })();
17319 }
17320 var ret = [ "if", c, t, e ];
17321 if (t[0] == "if" && empty(t[3]) && empty(e)) {
17322 ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ]));
17323 }
17324 else if (t[0] == "stat") {
17325 if (e) {
17326 if (e[0] == "stat")
17327 ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]);
17328 else if (aborts(e))
17329 ret = abort_else(c, t, e);
17330 }
17331 else {
17332 ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]);
17333 }
17334 }
17335 else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) {
17336 ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]);
17337 }
17338 else if (e && aborts(t)) {
17339 ret = [ [ "if", c, t ] ];
17340 if (e[0] == "block") {
17341 if (e[1]) ret = ret.concat(e[1]);
17342 }
17343 else {
17344 ret.push(e);
17345 }
17346 ret = walk([ "block", ret ]);
17347 }
17348 else if (t && aborts(e)) {
17349 ret = abort_else(c, t, e);
17350 }
17351 return ret;
17352 };
17353
17354 function _do_while(cond, body) {
17355 return when_constant(cond, function(cond, val){
17356 if (!val) {
17357 warn_unreachable(body);
17358 return [ "block" ];
17359 } else {
17360 return [ "for", null, null, null, walk(body) ];
17361 }
17362 });
17363 };
17364
17365 return w.with_walkers({
17366 "sub": function(expr, subscript) {
17367 if (subscript[0] == "string") {
17368 var name = subscript[1];
17369 if (is_identifier(name))
17370 return [ "dot", walk(expr), name ];
17371 else if (/^[1-9][0-9]*$/.test(name) || name === "0")
17372 return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ];
17373 }
17374 },
17375 "if": make_if,
17376 "toplevel": function(body) {
17377 return [ "toplevel", tighten(body) ];
17378 },
17379 "switch": function(expr, body) {
17380 var last = body.length - 1;
17381 return [ "switch", walk(expr), MAP(body, function(branch, i){
17382 var block = tighten(branch[1]);
17383 if (i == last && block.length > 0) {
17384 var node = block[block.length - 1];
17385 if (node[0] == "break" && !node[1])
17386 block.pop();
17387 }
17388 return [ branch[0] ? walk(branch[0]) : null, block ];
17389 }) ];
17390 },
17391 "function": _lambda,
17392 "defun": _lambda,
17393 "block": function(body) {
17394 if (body) return rmblock([ "block", tighten(body) ]);
17395 },
17396 "binary": function(op, left, right) {
17397 return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){
17398 return best_of(walk(c), this);
17399 }, function no() {
17400 return function(){
17401 if(op != "==" && op != "!=") return;
17402 var l = walk(left), r = walk(right);
17403 if(l && l[0] == "unary-prefix" && l[1] == "!" && l[2][0] == "num")
17404 left = ['num', +!l[2][1]];
17405 else if (r && r[0] == "unary-prefix" && r[1] == "!" && r[2][0] == "num")
17406 right = ['num', +!r[2][1]];
17407 return ["binary", op, left, right];
17408 }() || this;
17409 });
17410 },
17411 "conditional": function(c, t, e) {
17412 return make_conditional(walk(c), walk(t), walk(e));
17413 },
17414 "try": function(t, c, f) {
17415 return [
17416 "try",
17417 tighten(t),
17418 c != null ? [ c[0], tighten(c[1]) ] : null,
17419 f != null ? tighten(f) : null
17420 ];
17421 },
17422 "unary-prefix": function(op, expr) {
17423 expr = walk(expr);
17424 var ret = [ "unary-prefix", op, expr ];
17425 if (op == "!")
17426 ret = best_of(ret, negate(expr));
17427 return when_constant(ret, function(ast, val){
17428 return walk(ast); // it's either true or false, so minifies to !0 or !1
17429 }, function() { return ret });
17430 },
17431 "name": function(name) {
17432 switch (name) {
17433 case "true": return [ "unary-prefix", "!", [ "num", 0 ]];
17434 case "false": return [ "unary-prefix", "!", [ "num", 1 ]];
17435 }
17436 },
17437 "while": _do_while,
17438 "assign": function(op, lvalue, rvalue) {
17439 lvalue = walk(lvalue);
17440 rvalue = walk(rvalue);
17441 var okOps = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
17442 if (op === true && lvalue[0] === "name" && rvalue[0] === "binary" &&
17443 ~okOps.indexOf(rvalue[1]) && rvalue[2][0] === "name" &&
17444 rvalue[2][1] === lvalue[1]) {
17445 return [ this[0], rvalue[1], lvalue, rvalue[3] ]
17446 }
17447 return [ this[0], op, lvalue, rvalue ];
17448 },
17449 "call": function(expr, args) {
17450 expr = walk(expr);
17451 if (options.unsafe && expr[0] == "dot" && expr[1][0] == "string" && expr[2] == "toString") {
17452 return expr[1];
17453 }
17454 return [ this[0], expr, MAP(args, walk) ];
17455 },
17456 "num": function (num) {
17457 if (!isFinite(num))
17458 return [ "binary", "/", num === 1 / 0
17459 ? [ "num", 1 ] : num === -1 / 0
17460 ? [ "unary-prefix", "-", [ "num", 1 ] ]
17461 : [ "num", 0 ], [ "num", 0 ] ];
17462
17463 return [ this[0], num ];
17464 }
17465 }, function() {
17466 return walk(prepare_ifs(walk(prepare_ifs(ast))));
17467 });
17468};
17469
17470function squeeze_2(ast, options) {
17471 var w = ast_walker(), walk = w.walk, scope;
17472 function with_scope(s, cont) {
17473 var save = scope, ret;
17474 scope = s;
17475 ret = cont();
17476 scope = save;
17477 return ret;
17478 };
17479 function lambda(name, args, body) {
17480 return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
17481 };
17482 return w.with_walkers({
17483 "directive": function(dir) {
17484 if (scope.active_directive(dir))
17485 return [ "block" ];
17486 scope.directives.push(dir);
17487 },
17488 "toplevel": function(body) {
17489 return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
17490 },
17491 "function": lambda,
17492 "defun": lambda
17493 }, function(){
17494 return walk(ast_add_scope(ast));
17495 });
17496};
17497
17498/* -----[ re-generate code from the AST ]----- */
17499
17500var DOT_CALL_NO_PARENS = jsp.array_to_hash([
17501 "name",
17502 "array",
17503 "object",
17504 "string",
17505 "dot",
17506 "sub",
17507 "call",
17508 "regexp",
17509 "defun"
17510]);
17511
17512function make_string(str, ascii_only) {
17513 var dq = 0, sq = 0;
17514 str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
17515 switch (s) {
17516 case "\\": return "\\\\";
17517 case "\b": return "\\b";
17518 case "\f": return "\\f";
17519 case "\n": return "\\n";
17520 case "\r": return "\\r";
17521 case "\u2028": return "\\u2028";
17522 case "\u2029": return "\\u2029";
17523 case '"': ++dq; return '"';
17524 case "'": ++sq; return "'";
17525 case "\0": return "\\0";
17526 }
17527 return s;
17528 });
17529 if (ascii_only) str = to_ascii(str);
17530 if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
17531 else return '"' + str.replace(/\x22/g, '\\"') + '"';
17532};
17533
17534function to_ascii(str) {
17535 return str.replace(/[\u0080-\uffff]/g, function(ch) {
17536 var code = ch.charCodeAt(0).toString(16);
17537 while (code.length < 4) code = "0" + code;
17538 return "\\u" + code;
17539 });
17540};
17541
17542var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]);
17543
17544function gen_code(ast, options) {
17545 options = defaults(options, {
17546 indent_start : 0,
17547 indent_level : 4,
17548 quote_keys : false,
17549 space_colon : false,
17550 beautify : false,
17551 ascii_only : false,
17552 inline_script: false
17553 });
17554 var beautify = !!options.beautify;
17555 var indentation = 0,
17556 newline = beautify ? "\n" : "",
17557 space = beautify ? " " : "";
17558
17559 function encode_string(str) {
17560 var ret = make_string(str, options.ascii_only);
17561 if (options.inline_script)
17562 ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
17563 return ret;
17564 };
17565
17566 function make_name(name) {
17567 name = name.toString();
17568 if (options.ascii_only)
17569 name = to_ascii(name);
17570 return name;
17571 };
17572
17573 function indent(line) {
17574 if (line == null)
17575 line = "";
17576 if (beautify)
17577 line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line;
17578 return line;
17579 };
17580
17581 function with_indent(cont, incr) {
17582 if (incr == null) incr = 1;
17583 indentation += incr;
17584 try { return cont.apply(null, slice(arguments, 1)); }
17585 finally { indentation -= incr; }
17586 };
17587
17588 function last_char(str) {
17589 str = str.toString();
17590 return str.charAt(str.length - 1);
17591 };
17592
17593 function first_char(str) {
17594 return str.toString().charAt(0);
17595 };
17596
17597 function add_spaces(a) {
17598 if (beautify)
17599 return a.join(" ");
17600 var b = [];
17601 for (var i = 0; i < a.length; ++i) {
17602 var next = a[i + 1];
17603 b.push(a[i]);
17604 if (next &&
17605 ((is_identifier_char(last_char(a[i])) && (is_identifier_char(first_char(next))
17606 || first_char(next) == "\\")) ||
17607 (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString()) ||
17608 last_char(a[i]) == "/" && first_char(next) == "/"))) {
17609 b.push(" ");
17610 }
17611 }
17612 return b.join("");
17613 };
17614
17615 function add_commas(a) {
17616 return a.join("," + space);
17617 };
17618
17619 function parenthesize(expr) {
17620 var gen = make(expr);
17621 for (var i = 1; i < arguments.length; ++i) {
17622 var el = arguments[i];
17623 if ((el instanceof Function && el(expr)) || expr[0] == el)
17624 return "(" + gen + ")";
17625 }
17626 return gen;
17627 };
17628
17629 function best_of(a) {
17630 if (a.length == 1) {
17631 return a[0];
17632 }
17633 if (a.length == 2) {
17634 var b = a[1];
17635 a = a[0];
17636 return a.length <= b.length ? a : b;
17637 }
17638 return best_of([ a[0], best_of(a.slice(1)) ]);
17639 };
17640
17641 function needs_parens(expr) {
17642 if (expr[0] == "function" || expr[0] == "object") {
17643 // dot/call on a literal function requires the
17644 // function literal itself to be parenthesized
17645 // only if it's the first "thing" in a
17646 // statement. This means that the parent is
17647 // "stat", but it could also be a "seq" and
17648 // we're the first in this "seq" and the
17649 // parent is "stat", and so on. Messy stuff,
17650 // but it worths the trouble.
17651 var a = slice(w.stack()), self = a.pop(), p = a.pop();
17652 while (p) {
17653 if (p[0] == "stat") return true;
17654 if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) ||
17655 ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) {
17656 self = p;
17657 p = a.pop();
17658 } else {
17659 return false;
17660 }
17661 }
17662 }
17663 return !HOP(DOT_CALL_NO_PARENS, expr[0]);
17664 };
17665
17666 function make_num(num) {
17667 var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
17668 if (Math.floor(num) === num) {
17669 if (num >= 0) {
17670 a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
17671 "0" + num.toString(8)); // same.
17672 } else {
17673 a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
17674 "-0" + (-num).toString(8)); // same.
17675 }
17676 if ((m = /^(.*?)(0+)$/.exec(num))) {
17677 a.push(m[1] + "e" + m[2].length);
17678 }
17679 } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
17680 a.push(m[2] + "e-" + (m[1].length + m[2].length),
17681 str.substr(str.indexOf(".")));
17682 }
17683 return best_of(a);
17684 };
17685
17686 var w = ast_walker();
17687 var make = w.walk;
17688 return w.with_walkers({
17689 "string": encode_string,
17690 "num": make_num,
17691 "name": make_name,
17692 "debugger": function(){ return "debugger;" },
17693 "toplevel": function(statements) {
17694 return make_block_statements(statements)
17695 .join(newline + newline);
17696 },
17697 "splice": function(statements) {
17698 var parent = w.parent();
17699 if (HOP(SPLICE_NEEDS_BRACKETS, parent)) {
17700 // we need block brackets in this case
17701 return make_block.apply(this, arguments);
17702 } else {
17703 return MAP(make_block_statements(statements, true),
17704 function(line, i) {
17705 // the first line is already indented
17706 return i > 0 ? indent(line) : line;
17707 }).join(newline);
17708 }
17709 },
17710 "block": make_block,
17711 "var": function(defs) {
17712 return "var " + add_commas(MAP(defs, make_1vardef)) + ";";
17713 },
17714 "const": function(defs) {
17715 return "const " + add_commas(MAP(defs, make_1vardef)) + ";";
17716 },
17717 "try": function(tr, ca, fi) {
17718 var out = [ "try", make_block(tr) ];
17719 if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1]));
17720 if (fi) out.push("finally", make_block(fi));
17721 return add_spaces(out);
17722 },
17723 "throw": function(expr) {
17724 return add_spaces([ "throw", make(expr) ]) + ";";
17725 },
17726 "new": function(ctor, args) {
17727 args = args.length > 0 ? "(" + add_commas(MAP(args, function(expr){
17728 return parenthesize(expr, "seq");
17729 })) + ")" : "";
17730 return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){
17731 var w = ast_walker(), has_call = {};
17732 try {
17733 w.with_walkers({
17734 "call": function() { throw has_call },
17735 "function": function() { return this }
17736 }, function(){
17737 w.walk(expr);
17738 });
17739 } catch(ex) {
17740 if (ex === has_call)
17741 return true;
17742 throw ex;
17743 }
17744 }) + args ]);
17745 },
17746 "switch": function(expr, body) {
17747 return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]);
17748 },
17749 "break": function(label) {
17750 var out = "break";
17751 if (label != null)
17752 out += " " + make_name(label);
17753 return out + ";";
17754 },
17755 "continue": function(label) {
17756 var out = "continue";
17757 if (label != null)
17758 out += " " + make_name(label);
17759 return out + ";";
17760 },
17761 "conditional": function(co, th, el) {
17762 return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?",
17763 parenthesize(th, "seq"), ":",
17764 parenthesize(el, "seq") ]);
17765 },
17766 "assign": function(op, lvalue, rvalue) {
17767 if (op && op !== true) op += "=";
17768 else op = "=";
17769 return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]);
17770 },
17771 "dot": function(expr) {
17772 var out = make(expr), i = 1;
17773 if (expr[0] == "num") {
17774 if (!/[a-f.]/i.test(out))
17775 out += ".";
17776 } else if (expr[0] != "function" && needs_parens(expr))
17777 out = "(" + out + ")";
17778 while (i < arguments.length)
17779 out += "." + make_name(arguments[i++]);
17780 return out;
17781 },
17782 "call": function(func, args) {
17783 var f = make(func);
17784 if (f.charAt(0) != "(" && needs_parens(func))
17785 f = "(" + f + ")";
17786 return f + "(" + add_commas(MAP(args, function(expr){
17787 return parenthesize(expr, "seq");
17788 })) + ")";
17789 },
17790 "function": make_function,
17791 "defun": make_function,
17792 "if": function(co, th, el) {
17793 var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ];
17794 if (el) {
17795 out.push("else", make(el));
17796 }
17797 return add_spaces(out);
17798 },
17799 "for": function(init, cond, step, block) {
17800 var out = [ "for" ];
17801 init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space);
17802 cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space);
17803 step = (step != null ? make(step) : "").replace(/;*\s*$/, "");
17804 var args = init + cond + step;
17805 if (args == "; ; ") args = ";;";
17806 out.push("(" + args + ")", make(block));
17807 return add_spaces(out);
17808 },
17809 "for-in": function(vvar, key, hash, block) {
17810 return add_spaces([ "for", "(" +
17811 (vvar ? make(vvar).replace(/;+$/, "") : make(key)),
17812 "in",
17813 make(hash) + ")", make(block) ]);
17814 },
17815 "while": function(condition, block) {
17816 return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]);
17817 },
17818 "do": function(condition, block) {
17819 return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";";
17820 },
17821 "return": function(expr) {
17822 var out = [ "return" ];
17823 if (expr != null) out.push(make(expr));
17824 return add_spaces(out) + ";";
17825 },
17826 "binary": function(operator, lvalue, rvalue) {
17827 var left = make(lvalue), right = make(rvalue);
17828 // XXX: I'm pretty sure other cases will bite here.
17829 // we need to be smarter.
17830 // adding parens all the time is the safest bet.
17831 if (member(lvalue[0], [ "assign", "conditional", "seq" ]) ||
17832 lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]] ||
17833 lvalue[0] == "function" && needs_parens(this)) {
17834 left = "(" + left + ")";
17835 }
17836 if (member(rvalue[0], [ "assign", "conditional", "seq" ]) ||
17837 rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] &&
17838 !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) {
17839 right = "(" + right + ")";
17840 }
17841 else if (!beautify && options.inline_script && (operator == "<" || operator == "<<")
17842 && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) {
17843 right = " " + right;
17844 }
17845 return add_spaces([ left, operator, right ]);
17846 },
17847 "unary-prefix": function(operator, expr) {
17848 var val = make(expr);
17849 if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
17850 val = "(" + val + ")";
17851 return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val;
17852 },
17853 "unary-postfix": function(operator, expr) {
17854 var val = make(expr);
17855 if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr)))
17856 val = "(" + val + ")";
17857 return val + operator;
17858 },
17859 "sub": function(expr, subscript) {
17860 var hash = make(expr);
17861 if (needs_parens(expr))
17862 hash = "(" + hash + ")";
17863 return hash + "[" + make(subscript) + "]";
17864 },
17865 "object": function(props) {
17866 var obj_needs_parens = needs_parens(this);
17867 if (props.length == 0)
17868 return obj_needs_parens ? "({})" : "{}";
17869 var out = "{" + newline + with_indent(function(){
17870 return MAP(props, function(p){
17871 if (p.length == 3) {
17872 // getter/setter. The name is in p[0], the arg.list in p[1][2], the
17873 // body in p[1][3] and type ("get" / "set") in p[2].
17874 return indent(make_function(p[0], p[1][2], p[1][3], p[2], true));
17875 }
17876 var key = p[0], val = parenthesize(p[1], "seq");
17877 if (options.quote_keys) {
17878 key = encode_string(key);
17879 } else if ((typeof key == "number" || !beautify && +key + "" == key)
17880 && parseFloat(key) >= 0) {
17881 key = make_num(+key);
17882 } else if (!is_identifier(key)) {
17883 key = encode_string(key);
17884 }
17885 return indent(add_spaces(beautify && options.space_colon
17886 ? [ key, ":", val ]
17887 : [ key + ":", val ]));
17888 }).join("," + newline);
17889 }) + newline + indent("}");
17890 return obj_needs_parens ? "(" + out + ")" : out;
17891 },
17892 "regexp": function(rx, mods) {
17893 if (options.ascii_only) rx = to_ascii(rx);
17894 return "/" + rx + "/" + mods;
17895 },
17896 "array": function(elements) {
17897 if (elements.length == 0) return "[]";
17898 return add_spaces([ "[", add_commas(MAP(elements, function(el, i){
17899 if (!beautify && el[0] == "atom" && el[1] == "undefined") return i === elements.length - 1 ? "," : "";
17900 return parenthesize(el, "seq");
17901 })), "]" ]);
17902 },
17903 "stat": function(stmt) {
17904 return stmt != null
17905 ? make(stmt).replace(/;*\s*$/, ";")
17906 : ";";
17907 },
17908 "seq": function() {
17909 return add_commas(MAP(slice(arguments), make));
17910 },
17911 "label": function(name, block) {
17912 return add_spaces([ make_name(name), ":", make(block) ]);
17913 },
17914 "with": function(expr, block) {
17915 return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]);
17916 },
17917 "atom": function(name) {
17918 return make_name(name);
17919 },
17920 "directive": function(dir) {
17921 return make_string(dir) + ";";
17922 }
17923 }, function(){ return make(ast) });
17924
17925 // The squeezer replaces "block"-s that contain only a single
17926 // statement with the statement itself; technically, the AST
17927 // is correct, but this can create problems when we output an
17928 // IF having an ELSE clause where the THEN clause ends in an
17929 // IF *without* an ELSE block (then the outer ELSE would refer
17930 // to the inner IF). This function checks for this case and
17931 // adds the block brackets if needed.
17932 function make_then(th) {
17933 if (th == null) return ";";
17934 if (th[0] == "do") {
17935 // https://github.com/mishoo/UglifyJS/issues/#issue/57
17936 // IE croaks with "syntax error" on code like this:
17937 // if (foo) do ... while(cond); else ...
17938 // we need block brackets around do/while
17939 return make_block([ th ]);
17940 }
17941 var b = th;
17942 while (true) {
17943 var type = b[0];
17944 if (type == "if") {
17945 if (!b[3])
17946 // no else, we must add the block
17947 return make([ "block", [ th ]]);
17948 b = b[3];
17949 }
17950 else if (type == "while" || type == "do") b = b[2];
17951 else if (type == "for" || type == "for-in") b = b[4];
17952 else break;
17953 }
17954 return make(th);
17955 };
17956
17957 function make_function(name, args, body, keyword, no_parens) {
17958 var out = keyword || "function";
17959 if (name) {
17960 out += " " + make_name(name);
17961 }
17962 out += "(" + add_commas(MAP(args, make_name)) + ")";
17963 out = add_spaces([ out, make_block(body) ]);
17964 return (!no_parens && needs_parens(this)) ? "(" + out + ")" : out;
17965 };
17966
17967 function must_has_semicolon(node) {
17968 switch (node[0]) {
17969 case "with":
17970 case "while":
17971 return empty(node[2]) || must_has_semicolon(node[2]);
17972 case "for":
17973 case "for-in":
17974 return empty(node[4]) || must_has_semicolon(node[4]);
17975 case "if":
17976 if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else'
17977 if (node[3]) {
17978 if (empty(node[3])) return true; // `else' present but empty
17979 return must_has_semicolon(node[3]); // dive into the `else' branch
17980 }
17981 return must_has_semicolon(node[2]); // dive into the `then' branch
17982 case "directive":
17983 return true;
17984 }
17985 };
17986
17987 function make_block_statements(statements, noindent) {
17988 for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) {
17989 var stat = statements[i];
17990 var code = make(stat);
17991 if (code != ";") {
17992 if (!beautify && i == last && !must_has_semicolon(stat)) {
17993 code = code.replace(/;+\s*$/, "");
17994 }
17995 a.push(code);
17996 }
17997 }
17998 return noindent ? a : MAP(a, indent);
17999 };
18000
18001 function make_switch_block(body) {
18002 var n = body.length;
18003 if (n == 0) return "{}";
18004 return "{" + newline + MAP(body, function(branch, i){
18005 var has_body = branch[1].length > 0, code = with_indent(function(){
18006 return indent(branch[0]
18007 ? add_spaces([ "case", make(branch[0]) + ":" ])
18008 : "default:");
18009 }, 0.5) + (has_body ? newline + with_indent(function(){
18010 return make_block_statements(branch[1]).join(newline);
18011 }) : "");
18012 if (!beautify && has_body && i < n - 1)
18013 code += ";";
18014 return code;
18015 }).join(newline) + newline + indent("}");
18016 };
18017
18018 function make_block(statements) {
18019 if (!statements) return ";";
18020 if (statements.length == 0) return "{}";
18021 return "{" + newline + with_indent(function(){
18022 return make_block_statements(statements).join(newline);
18023 }) + newline + indent("}");
18024 };
18025
18026 function make_1vardef(def) {
18027 var name = def[0], val = def[1];
18028 if (val != null)
18029 name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]);
18030 return name;
18031 };
18032
18033};
18034
18035function split_lines(code, max_line_length) {
18036 var splits = [ 0 ];
18037 jsp.parse(function(){
18038 var next_token = jsp.tokenizer(code);
18039 var last_split = 0;
18040 var prev_token;
18041 function current_length(tok) {
18042 return tok.pos - last_split;
18043 };
18044 function split_here(tok) {
18045 last_split = tok.pos;
18046 splits.push(last_split);
18047 };
18048 function custom(){
18049 var tok = next_token.apply(this, arguments);
18050 out: {
18051 if (prev_token) {
18052 if (prev_token.type == "keyword") break out;
18053 }
18054 if (current_length(tok) > max_line_length) {
18055 switch (tok.type) {
18056 case "keyword":
18057 case "atom":
18058 case "name":
18059 case "punc":
18060 split_here(tok);
18061 break out;
18062 }
18063 }
18064 }
18065 prev_token = tok;
18066 return tok;
18067 };
18068 custom.context = function() {
18069 return next_token.context.apply(this, arguments);
18070 };
18071 return custom;
18072 }());
18073 return splits.map(function(pos, i){
18074 return code.substring(pos, splits[i + 1] || code.length);
18075 }).join("\n");
18076};
18077
18078/* -----[ Utilities ]----- */
18079
18080function repeat_string(str, i) {
18081 if (i <= 0) return "";
18082 if (i == 1) return str;
18083 var d = repeat_string(str, i >> 1);
18084 d += d;
18085 if (i & 1) d += str;
18086 return d;
18087};
18088
18089function defaults(args, defs) {
18090 var ret = {};
18091 if (args === true)
18092 args = {};
18093 for (var i in defs) if (HOP(defs, i)) {
18094 ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
18095 }
18096 return ret;
18097};
18098
18099function is_identifier(name) {
18100 return /^[a-z_$][a-z0-9_$]*$/i.test(name)
18101 && name != "this"
18102 && !HOP(jsp.KEYWORDS_ATOM, name)
18103 && !HOP(jsp.RESERVED_WORDS, name)
18104 && !HOP(jsp.KEYWORDS, name);
18105};
18106
18107function HOP(obj, prop) {
18108 return Object.prototype.hasOwnProperty.call(obj, prop);
18109};
18110
18111// some utilities
18112
18113var MAP;
18114
18115(function(){
18116 MAP = function(a, f, o) {
18117 var ret = [], top = [], i;
18118 function doit() {
18119 var val = f.call(o, a[i], i);
18120 if (val instanceof AtTop) {
18121 val = val.v;
18122 if (val instanceof Splice) {
18123 top.push.apply(top, val.v);
18124 } else {
18125 top.push(val);
18126 }
18127 }
18128 else if (val != skip) {
18129 if (val instanceof Splice) {
18130 ret.push.apply(ret, val.v);
18131 } else {
18132 ret.push(val);
18133 }
18134 }
18135 };
18136 if (a instanceof Array) for (i = 0; i < a.length; ++i) doit();
18137 else for (i in a) if (HOP(a, i)) doit();
18138 return top.concat(ret);
18139 };
18140 MAP.at_top = function(val) { return new AtTop(val) };
18141 MAP.splice = function(val) { return new Splice(val) };
18142 var skip = MAP.skip = {};
18143 function AtTop(val) { this.v = val };
18144 function Splice(val) { this.v = val };
18145})();
18146
18147/* -----[ Exports ]----- */
18148
18149exports.ast_walker = ast_walker;
18150exports.ast_mangle = ast_mangle;
18151exports.ast_squeeze = ast_squeeze;
18152exports.ast_lift_variables = ast_lift_variables;
18153exports.gen_code = gen_code;
18154exports.ast_add_scope = ast_add_scope;
18155exports.set_logger = function(logger) { warn = logger };
18156exports.make_string = make_string;
18157exports.split_lines = split_lines;
18158exports.MAP = MAP;
18159
18160// keep this last!
18161exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
18162
18163// Local variables:
18164// js-indent-level: 4
18165// End:
18166});
18167define('uglifyjs/index', ["require", "exports", "module", "./parse-js", "./process", "./consolidator"], function(require, exports, module) {
18168//convienence function(src, [options]);
18169function uglify(orig_code, options){
18170 options || (options = {});
18171 var jsp = uglify.parser;
18172 var pro = uglify.uglify;
18173
18174 var ast = jsp.parse(orig_code, options.strict_semicolons); // parse code and get the initial AST
18175 ast = pro.ast_mangle(ast, options.mangle_options); // get a new AST with mangled names
18176 ast = pro.ast_squeeze(ast, options.squeeze_options); // get an AST with compression optimizations
18177 var final_code = pro.gen_code(ast, options.gen_options); // compressed code here
18178 return final_code;
18179};
18180
18181uglify.parser = require("./parse-js");
18182uglify.uglify = require("./process");
18183uglify.consolidator = require("./consolidator");
18184
18185module.exports = uglify
18186});//Distributed under the BSD license:
18187//Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
18188define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], function (exports, MOZ_SourceMap, logger, rjsFile) {
18189
18190/***********************************************************************
18191
18192 A JavaScript tokenizer / parser / beautifier / compressor.
18193 https://github.com/mishoo/UglifyJS2
18194
18195 -------------------------------- (C) ---------------------------------
18196
18197 Author: Mihai Bazon
18198 <mihai.bazon@gmail.com>
18199 http://mihai.bazon.net/blog
18200
18201 Distributed under the BSD license:
18202
18203 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
18204
18205 Redistribution and use in source and binary forms, with or without
18206 modification, are permitted provided that the following conditions
18207 are met:
18208
18209 * Redistributions of source code must retain the above
18210 copyright notice, this list of conditions and the following
18211 disclaimer.
18212
18213 * Redistributions in binary form must reproduce the above
18214 copyright notice, this list of conditions and the following
18215 disclaimer in the documentation and/or other materials
18216 provided with the distribution.
18217
18218 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
18219 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18220 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18221 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
18222 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
18223 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18224 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18225 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18226 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
18227 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
18228 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18229 SUCH DAMAGE.
18230
18231 ***********************************************************************/
18232
18233"use strict";
18234
18235function array_to_hash(a) {
18236 var ret = Object.create(null);
18237 for (var i = 0; i < a.length; ++i)
18238 ret[a[i]] = true;
18239 return ret;
18240};
18241
18242function slice(a, start) {
18243 return Array.prototype.slice.call(a, start || 0);
18244};
18245
18246function characters(str) {
18247 return str.split("");
18248};
18249
18250function member(name, array) {
18251 for (var i = array.length; --i >= 0;)
18252 if (array[i] == name)
18253 return true;
18254 return false;
18255};
18256
18257function find_if(func, array) {
18258 for (var i = 0, n = array.length; i < n; ++i) {
18259 if (func(array[i]))
18260 return array[i];
18261 }
18262};
18263
18264function repeat_string(str, i) {
18265 if (i <= 0) return "";
18266 if (i == 1) return str;
18267 var d = repeat_string(str, i >> 1);
18268 d += d;
18269 if (i & 1) d += str;
18270 return d;
18271};
18272
18273function DefaultsError(msg, defs) {
18274 Error.call(this, msg);
18275 this.msg = msg;
18276 this.defs = defs;
18277};
18278DefaultsError.prototype = Object.create(Error.prototype);
18279DefaultsError.prototype.constructor = DefaultsError;
18280
18281DefaultsError.croak = function(msg, defs) {
18282 throw new DefaultsError(msg, defs);
18283};
18284
18285function defaults(args, defs, croak) {
18286 if (args === true)
18287 args = {};
18288 var ret = args || {};
18289 if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i))
18290 DefaultsError.croak("`" + i + "` is not a supported option", defs);
18291 for (var i in defs) if (defs.hasOwnProperty(i)) {
18292 ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
18293 }
18294 return ret;
18295};
18296
18297function merge(obj, ext) {
18298 var count = 0;
18299 for (var i in ext) if (ext.hasOwnProperty(i)) {
18300 obj[i] = ext[i];
18301 count++;
18302 }
18303 return count;
18304};
18305
18306function noop() {};
18307
18308var MAP = (function(){
18309 function MAP(a, f, backwards) {
18310 var ret = [], top = [], i;
18311 function doit() {
18312 var val = f(a[i], i);
18313 var is_last = val instanceof Last;
18314 if (is_last) val = val.v;
18315 if (val instanceof AtTop) {
18316 val = val.v;
18317 if (val instanceof Splice) {
18318 top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
18319 } else {
18320 top.push(val);
18321 }
18322 }
18323 else if (val !== skip) {
18324 if (val instanceof Splice) {
18325 ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
18326 } else {
18327 ret.push(val);
18328 }
18329 }
18330 return is_last;
18331 };
18332 if (a instanceof Array) {
18333 if (backwards) {
18334 for (i = a.length; --i >= 0;) if (doit()) break;
18335 ret.reverse();
18336 top.reverse();
18337 } else {
18338 for (i = 0; i < a.length; ++i) if (doit()) break;
18339 }
18340 }
18341 else {
18342 for (i in a) if (a.hasOwnProperty(i)) if (doit()) break;
18343 }
18344 return top.concat(ret);
18345 };
18346 MAP.at_top = function(val) { return new AtTop(val) };
18347 MAP.splice = function(val) { return new Splice(val) };
18348 MAP.last = function(val) { return new Last(val) };
18349 var skip = MAP.skip = {};
18350 function AtTop(val) { this.v = val };
18351 function Splice(val) { this.v = val };
18352 function Last(val) { this.v = val };
18353 return MAP;
18354})();
18355
18356function push_uniq(array, el) {
18357 if (array.indexOf(el) < 0)
18358 array.push(el);
18359};
18360
18361function string_template(text, props) {
18362 return text.replace(/\{(.+?)\}/g, function(str, p){
18363 return props[p];
18364 });
18365};
18366
18367function remove(array, el) {
18368 for (var i = array.length; --i >= 0;) {
18369 if (array[i] === el) array.splice(i, 1);
18370 }
18371};
18372
18373function mergeSort(array, cmp) {
18374 if (array.length < 2) return array.slice();
18375 function merge(a, b) {
18376 var r = [], ai = 0, bi = 0, i = 0;
18377 while (ai < a.length && bi < b.length) {
18378 cmp(a[ai], b[bi]) <= 0
18379 ? r[i++] = a[ai++]
18380 : r[i++] = b[bi++];
18381 }
18382 if (ai < a.length) r.push.apply(r, a.slice(ai));
18383 if (bi < b.length) r.push.apply(r, b.slice(bi));
18384 return r;
18385 };
18386 function _ms(a) {
18387 if (a.length <= 1)
18388 return a;
18389 var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
18390 left = _ms(left);
18391 right = _ms(right);
18392 return merge(left, right);
18393 };
18394 return _ms(array);
18395};
18396
18397function set_difference(a, b) {
18398 return a.filter(function(el){
18399 return b.indexOf(el) < 0;
18400 });
18401};
18402
18403function set_intersection(a, b) {
18404 return a.filter(function(el){
18405 return b.indexOf(el) >= 0;
18406 });
18407};
18408
18409// this function is taken from Acorn [1], written by Marijn Haverbeke
18410// [1] https://github.com/marijnh/acorn
18411function makePredicate(words) {
18412 if (!(words instanceof Array)) words = words.split(" ");
18413 var f = "", cats = [];
18414 out: for (var i = 0; i < words.length; ++i) {
18415 for (var j = 0; j < cats.length; ++j)
18416 if (cats[j][0].length == words[i].length) {
18417 cats[j].push(words[i]);
18418 continue out;
18419 }
18420 cats.push([words[i]]);
18421 }
18422 function compareTo(arr) {
18423 if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";";
18424 f += "switch(str){";
18425 for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":";
18426 f += "return true}return false;";
18427 }
18428 // When there are more than three length categories, an outer
18429 // switch first dispatches on the lengths, to save on comparisons.
18430 if (cats.length > 3) {
18431 cats.sort(function(a, b) {return b.length - a.length;});
18432 f += "switch(str.length){";
18433 for (var i = 0; i < cats.length; ++i) {
18434 var cat = cats[i];
18435 f += "case " + cat[0].length + ":";
18436 compareTo(cat);
18437 }
18438 f += "}";
18439 // Otherwise, simply generate a flat `switch` statement.
18440 } else {
18441 compareTo(words);
18442 }
18443 return new Function("str", f);
18444};
18445
18446function all(array, predicate) {
18447 for (var i = array.length; --i >= 0;)
18448 if (!predicate(array[i]))
18449 return false;
18450 return true;
18451};
18452
18453function Dictionary() {
18454 this._values = Object.create(null);
18455 this._size = 0;
18456};
18457Dictionary.prototype = {
18458 set: function(key, val) {
18459 if (!this.has(key)) ++this._size;
18460 this._values["$" + key] = val;
18461 return this;
18462 },
18463 add: function(key, val) {
18464 if (this.has(key)) {
18465 this.get(key).push(val);
18466 } else {
18467 this.set(key, [ val ]);
18468 }
18469 return this;
18470 },
18471 get: function(key) { return this._values["$" + key] },
18472 del: function(key) {
18473 if (this.has(key)) {
18474 --this._size;
18475 delete this._values["$" + key];
18476 }
18477 return this;
18478 },
18479 has: function(key) { return ("$" + key) in this._values },
18480 each: function(f) {
18481 for (var i in this._values)
18482 f(this._values[i], i.substr(1));
18483 },
18484 size: function() {
18485 return this._size;
18486 },
18487 map: function(f) {
18488 var ret = [];
18489 for (var i in this._values)
18490 ret.push(f(this._values[i], i.substr(1)));
18491 return ret;
18492 },
18493 toObject: function() { return this._values }
18494};
18495Dictionary.fromObject = function(obj) {
18496 var dict = new Dictionary();
18497 dict._size = merge(dict._values, obj);
18498 return dict;
18499};
18500
18501/***********************************************************************
18502
18503 A JavaScript tokenizer / parser / beautifier / compressor.
18504 https://github.com/mishoo/UglifyJS2
18505
18506 -------------------------------- (C) ---------------------------------
18507
18508 Author: Mihai Bazon
18509 <mihai.bazon@gmail.com>
18510 http://mihai.bazon.net/blog
18511
18512 Distributed under the BSD license:
18513
18514 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
18515
18516 Redistribution and use in source and binary forms, with or without
18517 modification, are permitted provided that the following conditions
18518 are met:
18519
18520 * Redistributions of source code must retain the above
18521 copyright notice, this list of conditions and the following
18522 disclaimer.
18523
18524 * Redistributions in binary form must reproduce the above
18525 copyright notice, this list of conditions and the following
18526 disclaimer in the documentation and/or other materials
18527 provided with the distribution.
18528
18529 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
18530 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18531 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18532 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
18533 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
18534 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
18535 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18536 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
18537 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
18538 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
18539 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18540 SUCH DAMAGE.
18541
18542 ***********************************************************************/
18543
18544"use strict";
18545
18546function DEFNODE(type, props, methods, base) {
18547 if (arguments.length < 4) base = AST_Node;
18548 if (!props) props = [];
18549 else props = props.split(/\s+/);
18550 var self_props = props;
18551 if (base && base.PROPS)
18552 props = props.concat(base.PROPS);
18553 var code = "return function AST_" + type + "(props){ if (props) { ";
18554 for (var i = props.length; --i >= 0;) {
18555 code += "this." + props[i] + " = props." + props[i] + ";";
18556 }
18557 var proto = base && new base;
18558 if (proto && proto.initialize || (methods && methods.initialize))
18559 code += "this.initialize();";
18560 code += "}}";
18561 var ctor = new Function(code)();
18562 if (proto) {
18563 ctor.prototype = proto;
18564 ctor.BASE = base;
18565 }
18566 if (base) base.SUBCLASSES.push(ctor);
18567 ctor.prototype.CTOR = ctor;
18568 ctor.PROPS = props || null;
18569 ctor.SELF_PROPS = self_props;
18570 ctor.SUBCLASSES = [];
18571 if (type) {
18572 ctor.prototype.TYPE = ctor.TYPE = type;
18573 }
18574 if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
18575 if (/^\$/.test(i)) {
18576 ctor[i.substr(1)] = methods[i];
18577 } else {
18578 ctor.prototype[i] = methods[i];
18579 }
18580 }
18581 ctor.DEFMETHOD = function(name, method) {
18582 this.prototype[name] = method;
18583 };
18584 exports["AST_" + type] = ctor;
18585 return ctor;
18586};
18587
18588var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
18589}, null);
18590
18591var AST_Node = DEFNODE("Node", "start end", {
18592 clone: function() {
18593 return new this.CTOR(this);
18594 },
18595 $documentation: "Base class of all AST nodes",
18596 $propdoc: {
18597 start: "[AST_Token] The first token of this node",
18598 end: "[AST_Token] The last token of this node"
18599 },
18600 _walk: function(visitor) {
18601 return visitor._visit(this);
18602 },
18603 walk: function(visitor) {
18604 return this._walk(visitor); // not sure the indirection will be any help
18605 }
18606}, null);
18607
18608AST_Node.warn_function = null;
18609AST_Node.warn = function(txt, props) {
18610 if (AST_Node.warn_function)
18611 AST_Node.warn_function(string_template(txt, props));
18612};
18613
18614/* -----[ statements ]----- */
18615
18616var AST_Statement = DEFNODE("Statement", null, {
18617 $documentation: "Base class of all statements",
18618});
18619
18620var AST_Debugger = DEFNODE("Debugger", null, {
18621 $documentation: "Represents a debugger statement",
18622}, AST_Statement);
18623
18624var AST_Directive = DEFNODE("Directive", "value scope quote", {
18625 $documentation: "Represents a directive, like \"use strict\";",
18626 $propdoc: {
18627 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
18628 scope: "[AST_Scope/S] The scope that this directive affects",
18629 quote: "[string] the original quote character"
18630 },
18631}, AST_Statement);
18632
18633var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
18634 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
18635 $propdoc: {
18636 body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
18637 },
18638 _walk: function(visitor) {
18639 return visitor._visit(this, function(){
18640 this.body._walk(visitor);
18641 });
18642 }
18643}, AST_Statement);
18644
18645function walk_body(node, visitor) {
18646 if (node.body instanceof AST_Statement) {
18647 node.body._walk(visitor);
18648 }
18649 else node.body.forEach(function(stat){
18650 stat._walk(visitor);
18651 });
18652};
18653
18654var AST_Block = DEFNODE("Block", "body", {
18655 $documentation: "A body of statements (usually bracketed)",
18656 $propdoc: {
18657 body: "[AST_Statement*] an array of statements"
18658 },
18659 _walk: function(visitor) {
18660 return visitor._visit(this, function(){
18661 walk_body(this, visitor);
18662 });
18663 }
18664}, AST_Statement);
18665
18666var AST_BlockStatement = DEFNODE("BlockStatement", null, {
18667 $documentation: "A block statement",
18668}, AST_Block);
18669
18670var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
18671 $documentation: "The empty statement (empty block or simply a semicolon)",
18672 _walk: function(visitor) {
18673 return visitor._visit(this);
18674 }
18675}, AST_Statement);
18676
18677var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
18678 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
18679 $propdoc: {
18680 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
18681 },
18682 _walk: function(visitor) {
18683 return visitor._visit(this, function(){
18684 this.body._walk(visitor);
18685 });
18686 }
18687}, AST_Statement);
18688
18689var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
18690 $documentation: "Statement with a label",
18691 $propdoc: {
18692 label: "[AST_Label] a label definition"
18693 },
18694 _walk: function(visitor) {
18695 return visitor._visit(this, function(){
18696 this.label._walk(visitor);
18697 this.body._walk(visitor);
18698 });
18699 }
18700}, AST_StatementWithBody);
18701
18702var AST_IterationStatement = DEFNODE("IterationStatement", null, {
18703 $documentation: "Internal class. All loops inherit from it."
18704}, AST_StatementWithBody);
18705
18706var AST_DWLoop = DEFNODE("DWLoop", "condition", {
18707 $documentation: "Base class for do/while statements",
18708 $propdoc: {
18709 condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
18710 }
18711}, AST_IterationStatement);
18712
18713var AST_Do = DEFNODE("Do", null, {
18714 $documentation: "A `do` statement",
18715 _walk: function(visitor) {
18716 return visitor._visit(this, function(){
18717 this.body._walk(visitor);
18718 this.condition._walk(visitor);
18719 });
18720 }
18721}, AST_DWLoop);
18722
18723var AST_While = DEFNODE("While", null, {
18724 $documentation: "A `while` statement",
18725 _walk: function(visitor) {
18726 return visitor._visit(this, function(){
18727 this.condition._walk(visitor);
18728 this.body._walk(visitor);
18729 });
18730 }
18731}, AST_DWLoop);
18732
18733var AST_For = DEFNODE("For", "init condition step", {
18734 $documentation: "A `for` statement",
18735 $propdoc: {
18736 init: "[AST_Node?] the `for` initialization code, or null if empty",
18737 condition: "[AST_Node?] the `for` termination clause, or null if empty",
18738 step: "[AST_Node?] the `for` update clause, or null if empty"
18739 },
18740 _walk: function(visitor) {
18741 return visitor._visit(this, function(){
18742 if (this.init) this.init._walk(visitor);
18743 if (this.condition) this.condition._walk(visitor);
18744 if (this.step) this.step._walk(visitor);
18745 this.body._walk(visitor);
18746 });
18747 }
18748}, AST_IterationStatement);
18749
18750var AST_ForIn = DEFNODE("ForIn", "init name object", {
18751 $documentation: "A `for ... in` statement",
18752 $propdoc: {
18753 init: "[AST_Node] the `for/in` initialization code",
18754 name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
18755 object: "[AST_Node] the object that we're looping through"
18756 },
18757 _walk: function(visitor) {
18758 return visitor._visit(this, function(){
18759 this.init._walk(visitor);
18760 this.object._walk(visitor);
18761 this.body._walk(visitor);
18762 });
18763 }
18764}, AST_IterationStatement);
18765
18766var AST_With = DEFNODE("With", "expression", {
18767 $documentation: "A `with` statement",
18768 $propdoc: {
18769 expression: "[AST_Node] the `with` expression"
18770 },
18771 _walk: function(visitor) {
18772 return visitor._visit(this, function(){
18773 this.expression._walk(visitor);
18774 this.body._walk(visitor);
18775 });
18776 }
18777}, AST_StatementWithBody);
18778
18779/* -----[ scope and functions ]----- */
18780
18781var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
18782 $documentation: "Base class for all statements introducing a lexical scope",
18783 $propdoc: {
18784 directives: "[string*/S] an array of directives declared in this scope",
18785 variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
18786 functions: "[Object/S] like `variables`, but only lists function declarations",
18787 uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
18788 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
18789 parent_scope: "[AST_Scope?/S] link to the parent scope",
18790 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
18791 cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
18792 },
18793}, AST_Block);
18794
18795var AST_Toplevel = DEFNODE("Toplevel", "globals", {
18796 $documentation: "The toplevel scope",
18797 $propdoc: {
18798 globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
18799 },
18800 wrap_enclose: function(arg_parameter_pairs) {
18801 var self = this;
18802 var args = [];
18803 var parameters = [];
18804
18805 arg_parameter_pairs.forEach(function(pair) {
18806 var splitAt = pair.lastIndexOf(":");
18807
18808 args.push(pair.substr(0, splitAt));
18809 parameters.push(pair.substr(splitAt + 1));
18810 });
18811
18812 var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
18813 wrapped_tl = parse(wrapped_tl);
18814 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
18815 if (node instanceof AST_Directive && node.value == "$ORIG") {
18816 return MAP.splice(self.body);
18817 }
18818 }));
18819 return wrapped_tl;
18820 },
18821 wrap_commonjs: function(name, export_all) {
18822 var self = this;
18823 var to_export = [];
18824 if (export_all) {
18825 self.figure_out_scope();
18826 self.walk(new TreeWalker(function(node){
18827 if (node instanceof AST_SymbolDeclaration && node.definition().global) {
18828 if (!find_if(function(n){ return n.name == node.name }, to_export))
18829 to_export.push(node);
18830 }
18831 }));
18832 }
18833 var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))";
18834 wrapped_tl = parse(wrapped_tl);
18835 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
18836 if (node instanceof AST_Directive) {
18837 switch (node.value) {
18838 case "$ORIG":
18839 return MAP.splice(self.body);
18840 case "$EXPORTS":
18841 var body = [];
18842 to_export.forEach(function(sym){
18843 body.push(new AST_SimpleStatement({
18844 body: new AST_Assign({
18845 left: new AST_Sub({
18846 expression: new AST_SymbolRef({ name: "exports" }),
18847 property: new AST_String({ value: sym.name }),
18848 }),
18849 operator: "=",
18850 right: new AST_SymbolRef(sym),
18851 }),
18852 }));
18853 });
18854 return MAP.splice(body);
18855 }
18856 }
18857 }));
18858 return wrapped_tl;
18859 }
18860}, AST_Scope);
18861
18862var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
18863 $documentation: "Base class for functions",
18864 $propdoc: {
18865 name: "[AST_SymbolDeclaration?] the name of this function",
18866 argnames: "[AST_SymbolFunarg*] array of function arguments",
18867 uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
18868 },
18869 _walk: function(visitor) {
18870 return visitor._visit(this, function(){
18871 if (this.name) this.name._walk(visitor);
18872 this.argnames.forEach(function(arg){
18873 arg._walk(visitor);
18874 });
18875 walk_body(this, visitor);
18876 });
18877 }
18878}, AST_Scope);
18879
18880var AST_Accessor = DEFNODE("Accessor", null, {
18881 $documentation: "A setter/getter function. The `name` property is always null."
18882}, AST_Lambda);
18883
18884var AST_Function = DEFNODE("Function", null, {
18885 $documentation: "A function expression"
18886}, AST_Lambda);
18887
18888var AST_Defun = DEFNODE("Defun", null, {
18889 $documentation: "A function definition"
18890}, AST_Lambda);
18891
18892/* -----[ JUMPS ]----- */
18893
18894var AST_Jump = DEFNODE("Jump", null, {
18895 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
18896}, AST_Statement);
18897
18898var AST_Exit = DEFNODE("Exit", "value", {
18899 $documentation: "Base class for “exits” (`return` and `throw`)",
18900 $propdoc: {
18901 value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
18902 },
18903 _walk: function(visitor) {
18904 return visitor._visit(this, this.value && function(){
18905 this.value._walk(visitor);
18906 });
18907 }
18908}, AST_Jump);
18909
18910var AST_Return = DEFNODE("Return", null, {
18911 $documentation: "A `return` statement"
18912}, AST_Exit);
18913
18914var AST_Throw = DEFNODE("Throw", null, {
18915 $documentation: "A `throw` statement"
18916}, AST_Exit);
18917
18918var AST_LoopControl = DEFNODE("LoopControl", "label", {
18919 $documentation: "Base class for loop control statements (`break` and `continue`)",
18920 $propdoc: {
18921 label: "[AST_LabelRef?] the label, or null if none",
18922 },
18923 _walk: function(visitor) {
18924 return visitor._visit(this, this.label && function(){
18925 this.label._walk(visitor);
18926 });
18927 }
18928}, AST_Jump);
18929
18930var AST_Break = DEFNODE("Break", null, {
18931 $documentation: "A `break` statement"
18932}, AST_LoopControl);
18933
18934var AST_Continue = DEFNODE("Continue", null, {
18935 $documentation: "A `continue` statement"
18936}, AST_LoopControl);
18937
18938/* -----[ IF ]----- */
18939
18940var AST_If = DEFNODE("If", "condition alternative", {
18941 $documentation: "A `if` statement",
18942 $propdoc: {
18943 condition: "[AST_Node] the `if` condition",
18944 alternative: "[AST_Statement?] the `else` part, or null if not present"
18945 },
18946 _walk: function(visitor) {
18947 return visitor._visit(this, function(){
18948 this.condition._walk(visitor);
18949 this.body._walk(visitor);
18950 if (this.alternative) this.alternative._walk(visitor);
18951 });
18952 }
18953}, AST_StatementWithBody);
18954
18955/* -----[ SWITCH ]----- */
18956
18957var AST_Switch = DEFNODE("Switch", "expression", {
18958 $documentation: "A `switch` statement",
18959 $propdoc: {
18960 expression: "[AST_Node] the `switch` “discriminant”"
18961 },
18962 _walk: function(visitor) {
18963 return visitor._visit(this, function(){
18964 this.expression._walk(visitor);
18965 walk_body(this, visitor);
18966 });
18967 }
18968}, AST_Block);
18969
18970var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
18971 $documentation: "Base class for `switch` branches",
18972}, AST_Block);
18973
18974var AST_Default = DEFNODE("Default", null, {
18975 $documentation: "A `default` switch branch",
18976}, AST_SwitchBranch);
18977
18978var AST_Case = DEFNODE("Case", "expression", {
18979 $documentation: "A `case` switch branch",
18980 $propdoc: {
18981 expression: "[AST_Node] the `case` expression"
18982 },
18983 _walk: function(visitor) {
18984 return visitor._visit(this, function(){
18985 this.expression._walk(visitor);
18986 walk_body(this, visitor);
18987 });
18988 }
18989}, AST_SwitchBranch);
18990
18991/* -----[ EXCEPTIONS ]----- */
18992
18993var AST_Try = DEFNODE("Try", "bcatch bfinally", {
18994 $documentation: "A `try` statement",
18995 $propdoc: {
18996 bcatch: "[AST_Catch?] the catch block, or null if not present",
18997 bfinally: "[AST_Finally?] the finally block, or null if not present"
18998 },
18999 _walk: function(visitor) {
19000 return visitor._visit(this, function(){
19001 walk_body(this, visitor);
19002 if (this.bcatch) this.bcatch._walk(visitor);
19003 if (this.bfinally) this.bfinally._walk(visitor);
19004 });
19005 }
19006}, AST_Block);
19007
19008var AST_Catch = DEFNODE("Catch", "argname", {
19009 $documentation: "A `catch` node; only makes sense as part of a `try` statement",
19010 $propdoc: {
19011 argname: "[AST_SymbolCatch] symbol for the exception"
19012 },
19013 _walk: function(visitor) {
19014 return visitor._visit(this, function(){
19015 this.argname._walk(visitor);
19016 walk_body(this, visitor);
19017 });
19018 }
19019}, AST_Block);
19020
19021var AST_Finally = DEFNODE("Finally", null, {
19022 $documentation: "A `finally` node; only makes sense as part of a `try` statement"
19023}, AST_Block);
19024
19025/* -----[ VAR/CONST ]----- */
19026
19027var AST_Definitions = DEFNODE("Definitions", "definitions", {
19028 $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
19029 $propdoc: {
19030 definitions: "[AST_VarDef*] array of variable definitions"
19031 },
19032 _walk: function(visitor) {
19033 return visitor._visit(this, function(){
19034 this.definitions.forEach(function(def){
19035 def._walk(visitor);
19036 });
19037 });
19038 }
19039}, AST_Statement);
19040
19041var AST_Var = DEFNODE("Var", null, {
19042 $documentation: "A `var` statement"
19043}, AST_Definitions);
19044
19045var AST_Const = DEFNODE("Const", null, {
19046 $documentation: "A `const` statement"
19047}, AST_Definitions);
19048
19049var AST_VarDef = DEFNODE("VarDef", "name value", {
19050 $documentation: "A variable declaration; only appears in a AST_Definitions node",
19051 $propdoc: {
19052 name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
19053 value: "[AST_Node?] initializer, or null of there's no initializer"
19054 },
19055 _walk: function(visitor) {
19056 return visitor._visit(this, function(){
19057 this.name._walk(visitor);
19058 if (this.value) this.value._walk(visitor);
19059 });
19060 }
19061});
19062
19063/* -----[ OTHER ]----- */
19064
19065var AST_Call = DEFNODE("Call", "expression args", {
19066 $documentation: "A function call expression",
19067 $propdoc: {
19068 expression: "[AST_Node] expression to invoke as function",
19069 args: "[AST_Node*] array of arguments"
19070 },
19071 _walk: function(visitor) {
19072 return visitor._visit(this, function(){
19073 this.expression._walk(visitor);
19074 this.args.forEach(function(arg){
19075 arg._walk(visitor);
19076 });
19077 });
19078 }
19079});
19080
19081var AST_New = DEFNODE("New", null, {
19082 $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
19083}, AST_Call);
19084
19085var AST_Seq = DEFNODE("Seq", "car cdr", {
19086 $documentation: "A sequence expression (two comma-separated expressions)",
19087 $propdoc: {
19088 car: "[AST_Node] first element in sequence",
19089 cdr: "[AST_Node] second element in sequence"
19090 },
19091 $cons: function(x, y) {
19092 var seq = new AST_Seq(x);
19093 seq.car = x;
19094 seq.cdr = y;
19095 return seq;
19096 },
19097 $from_array: function(array) {
19098 if (array.length == 0) return null;
19099 if (array.length == 1) return array[0].clone();
19100 var list = null;
19101 for (var i = array.length; --i >= 0;) {
19102 list = AST_Seq.cons(array[i], list);
19103 }
19104 var p = list;
19105 while (p) {
19106 if (p.cdr && !p.cdr.cdr) {
19107 p.cdr = p.cdr.car;
19108 break;
19109 }
19110 p = p.cdr;
19111 }
19112 return list;
19113 },
19114 to_array: function() {
19115 var p = this, a = [];
19116 while (p) {
19117 a.push(p.car);
19118 if (p.cdr && !(p.cdr instanceof AST_Seq)) {
19119 a.push(p.cdr);
19120 break;
19121 }
19122 p = p.cdr;
19123 }
19124 return a;
19125 },
19126 add: function(node) {
19127 var p = this;
19128 while (p) {
19129 if (!(p.cdr instanceof AST_Seq)) {
19130 var cell = AST_Seq.cons(p.cdr, node);
19131 return p.cdr = cell;
19132 }
19133 p = p.cdr;
19134 }
19135 },
19136 _walk: function(visitor) {
19137 return visitor._visit(this, function(){
19138 this.car._walk(visitor);
19139 if (this.cdr) this.cdr._walk(visitor);
19140 });
19141 }
19142});
19143
19144var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
19145 $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
19146 $propdoc: {
19147 expression: "[AST_Node] the “container” expression",
19148 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"
19149 }
19150});
19151
19152var AST_Dot = DEFNODE("Dot", null, {
19153 $documentation: "A dotted property access expression",
19154 _walk: function(visitor) {
19155 return visitor._visit(this, function(){
19156 this.expression._walk(visitor);
19157 });
19158 }
19159}, AST_PropAccess);
19160
19161var AST_Sub = DEFNODE("Sub", null, {
19162 $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
19163 _walk: function(visitor) {
19164 return visitor._visit(this, function(){
19165 this.expression._walk(visitor);
19166 this.property._walk(visitor);
19167 });
19168 }
19169}, AST_PropAccess);
19170
19171var AST_Unary = DEFNODE("Unary", "operator expression", {
19172 $documentation: "Base class for unary expressions",
19173 $propdoc: {
19174 operator: "[string] the operator",
19175 expression: "[AST_Node] expression that this unary operator applies to"
19176 },
19177 _walk: function(visitor) {
19178 return visitor._visit(this, function(){
19179 this.expression._walk(visitor);
19180 });
19181 }
19182});
19183
19184var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
19185 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
19186}, AST_Unary);
19187
19188var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
19189 $documentation: "Unary postfix expression, i.e. `i++`"
19190}, AST_Unary);
19191
19192var AST_Binary = DEFNODE("Binary", "left operator right", {
19193 $documentation: "Binary expression, i.e. `a + b`",
19194 $propdoc: {
19195 left: "[AST_Node] left-hand side expression",
19196 operator: "[string] the operator",
19197 right: "[AST_Node] right-hand side expression"
19198 },
19199 _walk: function(visitor) {
19200 return visitor._visit(this, function(){
19201 this.left._walk(visitor);
19202 this.right._walk(visitor);
19203 });
19204 }
19205});
19206
19207var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
19208 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
19209 $propdoc: {
19210 condition: "[AST_Node]",
19211 consequent: "[AST_Node]",
19212 alternative: "[AST_Node]"
19213 },
19214 _walk: function(visitor) {
19215 return visitor._visit(this, function(){
19216 this.condition._walk(visitor);
19217 this.consequent._walk(visitor);
19218 this.alternative._walk(visitor);
19219 });
19220 }
19221});
19222
19223var AST_Assign = DEFNODE("Assign", null, {
19224 $documentation: "An assignment expression — `a = b + 5`",
19225}, AST_Binary);
19226
19227/* -----[ LITERALS ]----- */
19228
19229var AST_Array = DEFNODE("Array", "elements", {
19230 $documentation: "An array literal",
19231 $propdoc: {
19232 elements: "[AST_Node*] array of elements"
19233 },
19234 _walk: function(visitor) {
19235 return visitor._visit(this, function(){
19236 this.elements.forEach(function(el){
19237 el._walk(visitor);
19238 });
19239 });
19240 }
19241});
19242
19243var AST_Object = DEFNODE("Object", "properties", {
19244 $documentation: "An object literal",
19245 $propdoc: {
19246 properties: "[AST_ObjectProperty*] array of properties"
19247 },
19248 _walk: function(visitor) {
19249 return visitor._visit(this, function(){
19250 this.properties.forEach(function(prop){
19251 prop._walk(visitor);
19252 });
19253 });
19254 }
19255});
19256
19257var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
19258 $documentation: "Base class for literal object properties",
19259 $propdoc: {
19260 key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
19261 value: "[AST_Node] property value. For setters and getters this is an AST_Function."
19262 },
19263 _walk: function(visitor) {
19264 return visitor._visit(this, function(){
19265 this.value._walk(visitor);
19266 });
19267 }
19268});
19269
19270var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
19271 $documentation: "A key: value object property",
19272 $propdoc: {
19273 quote: "[string] the original quote character"
19274 }
19275}, AST_ObjectProperty);
19276
19277var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
19278 $documentation: "An object setter property",
19279}, AST_ObjectProperty);
19280
19281var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
19282 $documentation: "An object getter property",
19283}, AST_ObjectProperty);
19284
19285var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
19286 $propdoc: {
19287 name: "[string] name of this symbol",
19288 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
19289 thedef: "[SymbolDef/S] the definition of this symbol"
19290 },
19291 $documentation: "Base class for all symbols",
19292});
19293
19294var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
19295 $documentation: "The name of a property accessor (setter/getter function)"
19296}, AST_Symbol);
19297
19298var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
19299 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
19300 $propdoc: {
19301 init: "[AST_Node*/S] array of initializers for this declaration."
19302 }
19303}, AST_Symbol);
19304
19305var AST_SymbolVar = DEFNODE("SymbolVar", null, {
19306 $documentation: "Symbol defining a variable",
19307}, AST_SymbolDeclaration);
19308
19309var AST_SymbolConst = DEFNODE("SymbolConst", null, {
19310 $documentation: "A constant declaration"
19311}, AST_SymbolDeclaration);
19312
19313var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
19314 $documentation: "Symbol naming a function argument",
19315}, AST_SymbolVar);
19316
19317var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
19318 $documentation: "Symbol defining a function",
19319}, AST_SymbolDeclaration);
19320
19321var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
19322 $documentation: "Symbol naming a function expression",
19323}, AST_SymbolDeclaration);
19324
19325var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
19326 $documentation: "Symbol naming the exception in catch",
19327}, AST_SymbolDeclaration);
19328
19329var AST_Label = DEFNODE("Label", "references", {
19330 $documentation: "Symbol naming a label (declaration)",
19331 $propdoc: {
19332 references: "[AST_LoopControl*] a list of nodes referring to this label"
19333 },
19334 initialize: function() {
19335 this.references = [];
19336 this.thedef = this;
19337 }
19338}, AST_Symbol);
19339
19340var AST_SymbolRef = DEFNODE("SymbolRef", null, {
19341 $documentation: "Reference to some symbol (not definition/declaration)",
19342}, AST_Symbol);
19343
19344var AST_LabelRef = DEFNODE("LabelRef", null, {
19345 $documentation: "Reference to a label symbol",
19346}, AST_Symbol);
19347
19348var AST_This = DEFNODE("This", null, {
19349 $documentation: "The `this` symbol",
19350}, AST_Symbol);
19351
19352var AST_Constant = DEFNODE("Constant", null, {
19353 $documentation: "Base class for all constants",
19354 getValue: function() {
19355 return this.value;
19356 }
19357});
19358
19359var AST_String = DEFNODE("String", "value quote", {
19360 $documentation: "A string literal",
19361 $propdoc: {
19362 value: "[string] the contents of this string",
19363 quote: "[string] the original quote character"
19364 }
19365}, AST_Constant);
19366
19367var AST_Number = DEFNODE("Number", "value literal", {
19368 $documentation: "A number literal",
19369 $propdoc: {
19370 value: "[number] the numeric value",
19371 literal: "[string] numeric value as string (optional)"
19372 }
19373}, AST_Constant);
19374
19375var AST_RegExp = DEFNODE("RegExp", "value", {
19376 $documentation: "A regexp literal",
19377 $propdoc: {
19378 value: "[RegExp] the actual regexp"
19379 }
19380}, AST_Constant);
19381
19382var AST_Atom = DEFNODE("Atom", null, {
19383 $documentation: "Base class for atoms",
19384}, AST_Constant);
19385
19386var AST_Null = DEFNODE("Null", null, {
19387 $documentation: "The `null` atom",
19388 value: null
19389}, AST_Atom);
19390
19391var AST_NaN = DEFNODE("NaN", null, {
19392 $documentation: "The impossible value",
19393 value: 0/0
19394}, AST_Atom);
19395
19396var AST_Undefined = DEFNODE("Undefined", null, {
19397 $documentation: "The `undefined` value",
19398 value: (function(){}())
19399}, AST_Atom);
19400
19401var AST_Hole = DEFNODE("Hole", null, {
19402 $documentation: "A hole in an array",
19403 value: (function(){}())
19404}, AST_Atom);
19405
19406var AST_Infinity = DEFNODE("Infinity", null, {
19407 $documentation: "The `Infinity` value",
19408 value: 1/0
19409}, AST_Atom);
19410
19411var AST_Boolean = DEFNODE("Boolean", null, {
19412 $documentation: "Base class for booleans",
19413}, AST_Atom);
19414
19415var AST_False = DEFNODE("False", null, {
19416 $documentation: "The `false` atom",
19417 value: false
19418}, AST_Boolean);
19419
19420var AST_True = DEFNODE("True", null, {
19421 $documentation: "The `true` atom",
19422 value: true
19423}, AST_Boolean);
19424
19425/* -----[ TreeWalker ]----- */
19426
19427function TreeWalker(callback) {
19428 this.visit = callback;
19429 this.stack = [];
19430 this.directives = Object.create(null);
19431};
19432TreeWalker.prototype = {
19433 _visit: function(node, descend) {
19434 this.push(node);
19435 var ret = this.visit(node, descend ? function(){
19436 descend.call(node);
19437 } : noop);
19438 if (!ret && descend) {
19439 descend.call(node);
19440 }
19441 this.pop(node);
19442 return ret;
19443 },
19444 parent: function(n) {
19445 return this.stack[this.stack.length - 2 - (n || 0)];
19446 },
19447 push: function (node) {
19448 if (node instanceof AST_Lambda) {
19449 this.directives = Object.create(this.directives);
19450 } else if (node instanceof AST_Directive) {
19451 this.directives[node.value] = this.directives[node.value] ? "up" : true;
19452 }
19453 this.stack.push(node);
19454 },
19455 pop: function(node) {
19456 this.stack.pop();
19457 if (node instanceof AST_Lambda) {
19458 this.directives = Object.getPrototypeOf(this.directives);
19459 }
19460 },
19461 self: function() {
19462 return this.stack[this.stack.length - 1];
19463 },
19464 find_parent: function(type) {
19465 var stack = this.stack;
19466 for (var i = stack.length; --i >= 0;) {
19467 var x = stack[i];
19468 if (x instanceof type) return x;
19469 }
19470 },
19471 has_directive: function(type) {
19472 var dir = this.directives[type];
19473 if (dir) return dir;
19474 var node = this.stack[this.stack.length - 1];
19475 if (node instanceof AST_Scope) {
19476 for (var i = 0; i < node.body.length; ++i) {
19477 var st = node.body[i];
19478 if (!(st instanceof AST_Directive)) break;
19479 if (st.value == type) return true;
19480 }
19481 }
19482 },
19483 in_boolean_context: function() {
19484 var stack = this.stack;
19485 var i = stack.length, self = stack[--i];
19486 while (i > 0) {
19487 var p = stack[--i];
19488 if ((p instanceof AST_If && p.condition === self) ||
19489 (p instanceof AST_Conditional && p.condition === self) ||
19490 (p instanceof AST_DWLoop && p.condition === self) ||
19491 (p instanceof AST_For && p.condition === self) ||
19492 (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
19493 {
19494 return true;
19495 }
19496 if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
19497 return false;
19498 self = p;
19499 }
19500 },
19501 loopcontrol_target: function(label) {
19502 var stack = this.stack;
19503 if (label) for (var i = stack.length; --i >= 0;) {
19504 var x = stack[i];
19505 if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
19506 return x.body;
19507 }
19508 } else for (var i = stack.length; --i >= 0;) {
19509 var x = stack[i];
19510 if (x instanceof AST_Switch || x instanceof AST_IterationStatement)
19511 return x;
19512 }
19513 }
19514};
19515
19516/***********************************************************************
19517
19518 A JavaScript tokenizer / parser / beautifier / compressor.
19519 https://github.com/mishoo/UglifyJS2
19520
19521 -------------------------------- (C) ---------------------------------
19522
19523 Author: Mihai Bazon
19524 <mihai.bazon@gmail.com>
19525 http://mihai.bazon.net/blog
19526
19527 Distributed under the BSD license:
19528
19529 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
19530 Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/).
19531
19532 Redistribution and use in source and binary forms, with or without
19533 modification, are permitted provided that the following conditions
19534 are met:
19535
19536 * Redistributions of source code must retain the above
19537 copyright notice, this list of conditions and the following
19538 disclaimer.
19539
19540 * Redistributions in binary form must reproduce the above
19541 copyright notice, this list of conditions and the following
19542 disclaimer in the documentation and/or other materials
19543 provided with the distribution.
19544
19545 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
19546 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19547 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19548 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
19549 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19550 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19551 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
19552 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19553 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
19554 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
19555 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19556 SUCH DAMAGE.
19557
19558 ***********************************************************************/
19559
19560"use strict";
19561
19562var 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';
19563var KEYWORDS_ATOM = 'false null true';
19564var 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 yield'
19565 + " " + KEYWORDS_ATOM + " " + KEYWORDS;
19566var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
19567
19568KEYWORDS = makePredicate(KEYWORDS);
19569RESERVED_WORDS = makePredicate(RESERVED_WORDS);
19570KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
19571KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
19572
19573var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
19574
19575var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
19576var RE_OCT_NUMBER = /^0[0-7]+$/;
19577
19578var OPERATORS = makePredicate([
19579 "in",
19580 "instanceof",
19581 "typeof",
19582 "new",
19583 "void",
19584 "delete",
19585 "++",
19586 "--",
19587 "+",
19588 "-",
19589 "!",
19590 "~",
19591 "&",
19592 "|",
19593 "^",
19594 "*",
19595 "/",
19596 "%",
19597 ">>",
19598 "<<",
19599 ">>>",
19600 "<",
19601 ">",
19602 "<=",
19603 ">=",
19604 "==",
19605 "===",
19606 "!=",
19607 "!==",
19608 "?",
19609 "=",
19610 "+=",
19611 "-=",
19612 "/=",
19613 "*=",
19614 "%=",
19615 ">>=",
19616 "<<=",
19617 ">>>=",
19618 "|=",
19619 "^=",
19620 "&=",
19621 "&&",
19622 "||"
19623]);
19624
19625var 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\uFEFF"));
19626
19627var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
19628
19629var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
19630
19631var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
19632
19633/* -----[ Tokenizer ]----- */
19634
19635// regexps adapted from http://xregexp.com/plugins/#unicode
19636var UNICODE = {
19637 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\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\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-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\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-\\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-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\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-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\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]"),
19638 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\\u0DE6-\\u0DEF\\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\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]"),
19639 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]"),
19640 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]"),
19641 connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
19642};
19643
19644function is_letter(code) {
19645 return (code >= 97 && code <= 122)
19646 || (code >= 65 && code <= 90)
19647 || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
19648};
19649
19650function is_digit(code) {
19651 return code >= 48 && code <= 57;
19652};
19653
19654function is_alphanumeric_char(code) {
19655 return is_digit(code) || is_letter(code);
19656};
19657
19658function is_unicode_digit(code) {
19659 return UNICODE.digit.test(String.fromCharCode(code));
19660}
19661
19662function is_unicode_combining_mark(ch) {
19663 return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
19664};
19665
19666function is_unicode_connector_punctuation(ch) {
19667 return UNICODE.connector_punctuation.test(ch);
19668};
19669
19670function is_identifier(name) {
19671 return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
19672};
19673
19674function is_identifier_start(code) {
19675 return code == 36 || code == 95 || is_letter(code);
19676};
19677
19678function is_identifier_char(ch) {
19679 var code = ch.charCodeAt(0);
19680 return is_identifier_start(code)
19681 || is_digit(code)
19682 || code == 8204 // \u200c: zero-width non-joiner <ZWNJ>
19683 || code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
19684 || is_unicode_combining_mark(ch)
19685 || is_unicode_connector_punctuation(ch)
19686 || is_unicode_digit(code)
19687 ;
19688};
19689
19690function is_identifier_string(str){
19691 return /^[a-z_$][a-z0-9_$]*$/i.test(str);
19692};
19693
19694function parse_js_number(num) {
19695 if (RE_HEX_NUMBER.test(num)) {
19696 return parseInt(num.substr(2), 16);
19697 } else if (RE_OCT_NUMBER.test(num)) {
19698 return parseInt(num.substr(1), 8);
19699 } else {
19700 var val = parseFloat(num);
19701 if (val == num) return val;
19702 }
19703};
19704
19705function JS_Parse_Error(message, filename, line, col, pos) {
19706 this.message = message;
19707 this.filename = filename;
19708 this.line = line;
19709 this.col = col;
19710 this.pos = pos;
19711 this.stack = new Error().stack;
19712};
19713
19714JS_Parse_Error.prototype.toString = function() {
19715 return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
19716};
19717
19718function js_error(message, filename, line, col, pos) {
19719 throw new JS_Parse_Error(message, filename, line, col, pos);
19720};
19721
19722function is_token(token, type, val) {
19723 return token.type == type && (val == null || token.value == val);
19724};
19725
19726var EX_EOF = {};
19727
19728function tokenizer($TEXT, filename, html5_comments, shebang) {
19729
19730 var S = {
19731 text : $TEXT,
19732 filename : filename,
19733 pos : 0,
19734 tokpos : 0,
19735 line : 1,
19736 tokline : 0,
19737 col : 0,
19738 tokcol : 0,
19739 newline_before : false,
19740 regex_allowed : false,
19741 comments_before : []
19742 };
19743
19744 function peek() { return S.text.charAt(S.pos); };
19745
19746 function next(signal_eof, in_string) {
19747 var ch = S.text.charAt(S.pos++);
19748 if (signal_eof && !ch)
19749 throw EX_EOF;
19750 if ("\r\n\u2028\u2029".indexOf(ch) >= 0) {
19751 S.newline_before = S.newline_before || !in_string;
19752 ++S.line;
19753 S.col = 0;
19754 if (!in_string && ch == "\r" && peek() == "\n") {
19755 // treat a \r\n sequence as a single \n
19756 ++S.pos;
19757 ch = "\n";
19758 }
19759 } else {
19760 ++S.col;
19761 }
19762 return ch;
19763 };
19764
19765 function forward(i) {
19766 while (i-- > 0) next();
19767 };
19768
19769 function looking_at(str) {
19770 return S.text.substr(S.pos, str.length) == str;
19771 };
19772
19773 function find(what, signal_eof) {
19774 var pos = S.text.indexOf(what, S.pos);
19775 if (signal_eof && pos == -1) throw EX_EOF;
19776 return pos;
19777 };
19778
19779 function start_token() {
19780 S.tokline = S.line;
19781 S.tokcol = S.col;
19782 S.tokpos = S.pos;
19783 };
19784
19785 var prev_was_dot = false;
19786 function token(type, value, is_comment) {
19787 S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
19788 (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
19789 (type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
19790 prev_was_dot = (type == "punc" && value == ".");
19791 var ret = {
19792 type : type,
19793 value : value,
19794 line : S.tokline,
19795 col : S.tokcol,
19796 pos : S.tokpos,
19797 endline : S.line,
19798 endcol : S.col,
19799 endpos : S.pos,
19800 nlb : S.newline_before,
19801 file : filename
19802 };
19803 if (/^(?:num|string|regexp)$/i.test(type)) {
19804 ret.raw = $TEXT.substring(ret.pos, ret.endpos);
19805 }
19806 if (!is_comment) {
19807 ret.comments_before = S.comments_before;
19808 S.comments_before = [];
19809 // make note of any newlines in the comments that came before
19810 for (var i = 0, len = ret.comments_before.length; i < len; i++) {
19811 ret.nlb = ret.nlb || ret.comments_before[i].nlb;
19812 }
19813 }
19814 S.newline_before = false;
19815 return new AST_Token(ret);
19816 };
19817
19818 function skip_whitespace() {
19819 var ch;
19820 while (WHITESPACE_CHARS(ch = peek()) || ch == "\u2028" || ch == "\u2029")
19821 next();
19822 };
19823
19824 function read_while(pred) {
19825 var ret = "", ch, i = 0;
19826 while ((ch = peek()) && pred(ch, i++))
19827 ret += next();
19828 return ret;
19829 };
19830
19831 function parse_error(err) {
19832 js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
19833 };
19834
19835 function read_num(prefix) {
19836 var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
19837 var num = read_while(function(ch, i){
19838 var code = ch.charCodeAt(0);
19839 switch (code) {
19840 case 120: case 88: // xX
19841 return has_x ? false : (has_x = true);
19842 case 101: case 69: // eE
19843 return has_x ? true : has_e ? false : (has_e = after_e = true);
19844 case 45: // -
19845 return after_e || (i == 0 && !prefix);
19846 case 43: // +
19847 return after_e;
19848 case (after_e = false, 46): // .
19849 return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
19850 }
19851 return is_alphanumeric_char(code);
19852 });
19853 if (prefix) num = prefix + num;
19854 var valid = parse_js_number(num);
19855 if (!isNaN(valid)) {
19856 return token("num", valid);
19857 } else {
19858 parse_error("Invalid syntax: " + num);
19859 }
19860 };
19861
19862 function read_escaped_char(in_string) {
19863 var ch = next(true, in_string);
19864 switch (ch.charCodeAt(0)) {
19865 case 110 : return "\n";
19866 case 114 : return "\r";
19867 case 116 : return "\t";
19868 case 98 : return "\b";
19869 case 118 : return "\u000b"; // \v
19870 case 102 : return "\f";
19871 case 48 : return "\0";
19872 case 120 : return String.fromCharCode(hex_bytes(2)); // \x
19873 case 117 : return String.fromCharCode(hex_bytes(4)); // \u
19874 case 10 : return ""; // newline
19875 case 13 : // \r
19876 if (peek() == "\n") { // DOS newline
19877 next(true, in_string);
19878 return "";
19879 }
19880 }
19881 return ch;
19882 };
19883
19884 function hex_bytes(n) {
19885 var num = 0;
19886 for (; n > 0; --n) {
19887 var digit = parseInt(next(true), 16);
19888 if (isNaN(digit))
19889 parse_error("Invalid hex-character pattern in string");
19890 num = (num << 4) | digit;
19891 }
19892 return num;
19893 };
19894
19895 var read_string = with_eof_error("Unterminated string constant", function(quote_char){
19896 var quote = next(), ret = "";
19897 for (;;) {
19898 var ch = next(true, true);
19899 if (ch == "\\") {
19900 // read OctalEscapeSequence (XXX: deprecated if "strict mode")
19901 // https://github.com/mishoo/UglifyJS/issues/178
19902 var octal_len = 0, first = null;
19903 ch = read_while(function(ch){
19904 if (ch >= "0" && ch <= "7") {
19905 if (!first) {
19906 first = ch;
19907 return ++octal_len;
19908 }
19909 else if (first <= "3" && octal_len <= 2) return ++octal_len;
19910 else if (first >= "4" && octal_len <= 1) return ++octal_len;
19911 }
19912 return false;
19913 });
19914 if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
19915 else ch = read_escaped_char(true);
19916 }
19917 else if (ch == quote) break;
19918 ret += ch;
19919 }
19920 var tok = token("string", ret);
19921 tok.quote = quote_char;
19922 return tok;
19923 });
19924
19925 function skip_line_comment(type) {
19926 var regex_allowed = S.regex_allowed;
19927 var i = find("\n"), ret;
19928 if (i == -1) {
19929 ret = S.text.substr(S.pos);
19930 S.pos = S.text.length;
19931 } else {
19932 ret = S.text.substring(S.pos, i);
19933 S.pos = i;
19934 }
19935 S.col = S.tokcol + (S.pos - S.tokpos);
19936 S.comments_before.push(token(type, ret, true));
19937 S.regex_allowed = regex_allowed;
19938 return next_token();
19939 };
19940
19941 var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
19942 var regex_allowed = S.regex_allowed;
19943 var i = find("*/", true);
19944 var text = S.text.substring(S.pos, i);
19945 var a = text.split("\n"), n = a.length;
19946 // update stream position
19947 S.pos = i + 2;
19948 S.line += n - 1;
19949 if (n > 1) S.col = a[n - 1].length;
19950 else S.col += a[n - 1].length;
19951 S.col += 2;
19952 var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
19953 S.comments_before.push(token("comment2", text, true));
19954 S.regex_allowed = regex_allowed;
19955 S.newline_before = nlb;
19956 return next_token();
19957 });
19958
19959 function read_name() {
19960 var backslash = false, name = "", ch, escaped = false, hex;
19961 while ((ch = peek()) != null) {
19962 if (!backslash) {
19963 if (ch == "\\") escaped = backslash = true, next();
19964 else if (is_identifier_char(ch)) name += next();
19965 else break;
19966 }
19967 else {
19968 if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
19969 ch = read_escaped_char();
19970 if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
19971 name += ch;
19972 backslash = false;
19973 }
19974 }
19975 if (KEYWORDS(name) && escaped) {
19976 hex = name.charCodeAt(0).toString(16).toUpperCase();
19977 name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
19978 }
19979 return name;
19980 };
19981
19982 var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
19983 var prev_backslash = false, ch, in_class = false;
19984 while ((ch = next(true))) if (prev_backslash) {
19985 regexp += "\\" + ch;
19986 prev_backslash = false;
19987 } else if (ch == "[") {
19988 in_class = true;
19989 regexp += ch;
19990 } else if (ch == "]" && in_class) {
19991 in_class = false;
19992 regexp += ch;
19993 } else if (ch == "/" && !in_class) {
19994 break;
19995 } else if (ch == "\\") {
19996 prev_backslash = true;
19997 } else {
19998 regexp += ch;
19999 }
20000 var mods = read_name();
20001 try {
20002 return token("regexp", new RegExp(regexp, mods));
20003 } catch(e) {
20004 parse_error(e.message);
20005 }
20006 });
20007
20008 function read_operator(prefix) {
20009 function grow(op) {
20010 if (!peek()) return op;
20011 var bigger = op + peek();
20012 if (OPERATORS(bigger)) {
20013 next();
20014 return grow(bigger);
20015 } else {
20016 return op;
20017 }
20018 };
20019 return token("operator", grow(prefix || next()));
20020 };
20021
20022 function handle_slash() {
20023 next();
20024 switch (peek()) {
20025 case "/":
20026 next();
20027 return skip_line_comment("comment1");
20028 case "*":
20029 next();
20030 return skip_multiline_comment();
20031 }
20032 return S.regex_allowed ? read_regexp("") : read_operator("/");
20033 };
20034
20035 function handle_dot() {
20036 next();
20037 return is_digit(peek().charCodeAt(0))
20038 ? read_num(".")
20039 : token("punc", ".");
20040 };
20041
20042 function read_word() {
20043 var word = read_name();
20044 if (prev_was_dot) return token("name", word);
20045 return KEYWORDS_ATOM(word) ? token("atom", word)
20046 : !KEYWORDS(word) ? token("name", word)
20047 : OPERATORS(word) ? token("operator", word)
20048 : token("keyword", word);
20049 };
20050
20051 function with_eof_error(eof_error, cont) {
20052 return function(x) {
20053 try {
20054 return cont(x);
20055 } catch(ex) {
20056 if (ex === EX_EOF) parse_error(eof_error);
20057 else throw ex;
20058 }
20059 };
20060 };
20061
20062 function next_token(force_regexp) {
20063 if (force_regexp != null)
20064 return read_regexp(force_regexp);
20065 skip_whitespace();
20066 start_token();
20067 if (html5_comments) {
20068 if (looking_at("<!--")) {
20069 forward(4);
20070 return skip_line_comment("comment3");
20071 }
20072 if (looking_at("-->") && S.newline_before) {
20073 forward(3);
20074 return skip_line_comment("comment4");
20075 }
20076 }
20077 var ch = peek();
20078 if (!ch) return token("eof");
20079 var code = ch.charCodeAt(0);
20080 switch (code) {
20081 case 34: case 39: return read_string(ch);
20082 case 46: return handle_dot();
20083 case 47: return handle_slash();
20084 }
20085 if (is_digit(code)) return read_num();
20086 if (PUNC_CHARS(ch)) return token("punc", next());
20087 if (OPERATOR_CHARS(ch)) return read_operator();
20088 if (code == 92 || is_identifier_start(code)) return read_word();
20089
20090 if (shebang) {
20091 if (S.pos == 0 && looking_at("#!")) {
20092 forward(2);
20093 return skip_line_comment("comment5");
20094 }
20095 }
20096 parse_error("Unexpected character '" + ch + "'");
20097 };
20098
20099 next_token.context = function(nc) {
20100 if (nc) S = nc;
20101 return S;
20102 };
20103
20104 return next_token;
20105
20106};
20107
20108/* -----[ Parser (constants) ]----- */
20109
20110var UNARY_PREFIX = makePredicate([
20111 "typeof",
20112 "void",
20113 "delete",
20114 "--",
20115 "++",
20116 "!",
20117 "~",
20118 "-",
20119 "+"
20120]);
20121
20122var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
20123
20124var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
20125
20126var PRECEDENCE = (function(a, ret){
20127 for (var i = 0; i < a.length; ++i) {
20128 var b = a[i];
20129 for (var j = 0; j < b.length; ++j) {
20130 ret[b[j]] = i + 1;
20131 }
20132 }
20133 return ret;
20134})(
20135 [
20136 ["||"],
20137 ["&&"],
20138 ["|"],
20139 ["^"],
20140 ["&"],
20141 ["==", "===", "!=", "!=="],
20142 ["<", ">", "<=", ">=", "in", "instanceof"],
20143 [">>", "<<", ">>>"],
20144 ["+", "-"],
20145 ["*", "/", "%"]
20146 ],
20147 {}
20148);
20149
20150var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
20151
20152var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
20153
20154/* -----[ Parser ]----- */
20155
20156function parse($TEXT, options) {
20157
20158 options = defaults(options, {
20159 strict : false,
20160 filename : null,
20161 toplevel : null,
20162 expression : false,
20163 html5_comments : true,
20164 bare_returns : false,
20165 shebang : true,
20166 });
20167
20168 var S = {
20169 input : (typeof $TEXT == "string"
20170 ? tokenizer($TEXT, options.filename,
20171 options.html5_comments, options.shebang)
20172 : $TEXT),
20173 token : null,
20174 prev : null,
20175 peeked : null,
20176 in_function : 0,
20177 in_directives : true,
20178 in_loop : 0,
20179 labels : []
20180 };
20181
20182 S.token = next();
20183
20184 function is(type, value) {
20185 return is_token(S.token, type, value);
20186 };
20187
20188 function peek() { return S.peeked || (S.peeked = S.input()); };
20189
20190 function next() {
20191 S.prev = S.token;
20192 if (S.peeked) {
20193 S.token = S.peeked;
20194 S.peeked = null;
20195 } else {
20196 S.token = S.input();
20197 }
20198 S.in_directives = S.in_directives && (
20199 S.token.type == "string" || is("punc", ";")
20200 );
20201 return S.token;
20202 };
20203
20204 function prev() {
20205 return S.prev;
20206 };
20207
20208 function croak(msg, line, col, pos) {
20209 var ctx = S.input.context();
20210 js_error(msg,
20211 ctx.filename,
20212 line != null ? line : ctx.tokline,
20213 col != null ? col : ctx.tokcol,
20214 pos != null ? pos : ctx.tokpos);
20215 };
20216
20217 function token_error(token, msg) {
20218 croak(msg, token.line, token.col);
20219 };
20220
20221 function unexpected(token) {
20222 if (token == null)
20223 token = S.token;
20224 token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
20225 };
20226
20227 function expect_token(type, val) {
20228 if (is(type, val)) {
20229 return next();
20230 }
20231 token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
20232 };
20233
20234 function expect(punc) { return expect_token("punc", punc); };
20235
20236 function can_insert_semicolon() {
20237 return !options.strict && (
20238 S.token.nlb || is("eof") || is("punc", "}")
20239 );
20240 };
20241
20242 function semicolon() {
20243 if (is("punc", ";")) next();
20244 else if (!can_insert_semicolon()) unexpected();
20245 };
20246
20247 function parenthesised() {
20248 expect("(");
20249 var exp = expression(true);
20250 expect(")");
20251 return exp;
20252 };
20253
20254 function embed_tokens(parser) {
20255 return function() {
20256 var start = S.token;
20257 var expr = parser();
20258 var end = prev();
20259 expr.start = start;
20260 expr.end = end;
20261 return expr;
20262 };
20263 };
20264
20265 function handle_regexp() {
20266 if (is("operator", "/") || is("operator", "/=")) {
20267 S.peeked = null;
20268 S.token = S.input(S.token.value.substr(1)); // force regexp
20269 }
20270 };
20271
20272 var statement = embed_tokens(function() {
20273 var tmp;
20274 handle_regexp();
20275 switch (S.token.type) {
20276 case "string":
20277 var dir = S.in_directives, stat = simple_statement();
20278 // XXXv2: decide how to fix directives
20279 if (dir && stat.body instanceof AST_String && !is("punc", ",")) {
20280 return new AST_Directive({
20281 start : stat.body.start,
20282 end : stat.body.end,
20283 quote : stat.body.quote,
20284 value : stat.body.value,
20285 });
20286 }
20287 return stat;
20288 case "num":
20289 case "regexp":
20290 case "operator":
20291 case "atom":
20292 return simple_statement();
20293
20294 case "name":
20295 return is_token(peek(), "punc", ":")
20296 ? labeled_statement()
20297 : simple_statement();
20298
20299 case "punc":
20300 switch (S.token.value) {
20301 case "{":
20302 return new AST_BlockStatement({
20303 start : S.token,
20304 body : block_(),
20305 end : prev()
20306 });
20307 case "[":
20308 case "(":
20309 return simple_statement();
20310 case ";":
20311 next();
20312 return new AST_EmptyStatement();
20313 default:
20314 unexpected();
20315 }
20316
20317 case "keyword":
20318 switch (tmp = S.token.value, next(), tmp) {
20319 case "break":
20320 return break_cont(AST_Break);
20321
20322 case "continue":
20323 return break_cont(AST_Continue);
20324
20325 case "debugger":
20326 semicolon();
20327 return new AST_Debugger();
20328
20329 case "do":
20330 return new AST_Do({
20331 body : in_loop(statement),
20332 condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp)
20333 });
20334
20335 case "while":
20336 return new AST_While({
20337 condition : parenthesised(),
20338 body : in_loop(statement)
20339 });
20340
20341 case "for":
20342 return for_();
20343
20344 case "function":
20345 return function_(AST_Defun);
20346
20347 case "if":
20348 return if_();
20349
20350 case "return":
20351 if (S.in_function == 0 && !options.bare_returns)
20352 croak("'return' outside of function");
20353 return new AST_Return({
20354 value: ( is("punc", ";")
20355 ? (next(), null)
20356 : can_insert_semicolon()
20357 ? null
20358 : (tmp = expression(true), semicolon(), tmp) )
20359 });
20360
20361 case "switch":
20362 return new AST_Switch({
20363 expression : parenthesised(),
20364 body : in_loop(switch_body_)
20365 });
20366
20367 case "throw":
20368 if (S.token.nlb)
20369 croak("Illegal newline after 'throw'");
20370 return new AST_Throw({
20371 value: (tmp = expression(true), semicolon(), tmp)
20372 });
20373
20374 case "try":
20375 return try_();
20376
20377 case "var":
20378 return tmp = var_(), semicolon(), tmp;
20379
20380 case "const":
20381 return tmp = const_(), semicolon(), tmp;
20382
20383 case "with":
20384 return new AST_With({
20385 expression : parenthesised(),
20386 body : statement()
20387 });
20388
20389 default:
20390 unexpected();
20391 }
20392 }
20393 });
20394
20395 function labeled_statement() {
20396 var label = as_symbol(AST_Label);
20397 if (find_if(function(l){ return l.name == label.name }, S.labels)) {
20398 // ECMA-262, 12.12: An ECMAScript program is considered
20399 // syntactically incorrect if it contains a
20400 // LabelledStatement that is enclosed by a
20401 // LabelledStatement with the same Identifier as label.
20402 croak("Label " + label.name + " defined twice");
20403 }
20404 expect(":");
20405 S.labels.push(label);
20406 var stat = statement();
20407 S.labels.pop();
20408 if (!(stat instanceof AST_IterationStatement)) {
20409 // check for `continue` that refers to this label.
20410 // those should be reported as syntax errors.
20411 // https://github.com/mishoo/UglifyJS2/issues/287
20412 label.references.forEach(function(ref){
20413 if (ref instanceof AST_Continue) {
20414 ref = ref.label.start;
20415 croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
20416 ref.line, ref.col, ref.pos);
20417 }
20418 });
20419 }
20420 return new AST_LabeledStatement({ body: stat, label: label });
20421 };
20422
20423 function simple_statement(tmp) {
20424 return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
20425 };
20426
20427 function break_cont(type) {
20428 var label = null, ldef;
20429 if (!can_insert_semicolon()) {
20430 label = as_symbol(AST_LabelRef, true);
20431 }
20432 if (label != null) {
20433 ldef = find_if(function(l){ return l.name == label.name }, S.labels);
20434 if (!ldef)
20435 croak("Undefined label " + label.name);
20436 label.thedef = ldef;
20437 }
20438 else if (S.in_loop == 0)
20439 croak(type.TYPE + " not inside a loop or switch");
20440 semicolon();
20441 var stat = new type({ label: label });
20442 if (ldef) ldef.references.push(stat);
20443 return stat;
20444 };
20445
20446 function for_() {
20447 expect("(");
20448 var init = null;
20449 if (!is("punc", ";")) {
20450 init = is("keyword", "var")
20451 ? (next(), var_(true))
20452 : expression(true, true);
20453 if (is("operator", "in")) {
20454 if (init instanceof AST_Var && init.definitions.length > 1)
20455 croak("Only one variable declaration allowed in for..in loop");
20456 next();
20457 return for_in(init);
20458 }
20459 }
20460 return regular_for(init);
20461 };
20462
20463 function regular_for(init) {
20464 expect(";");
20465 var test = is("punc", ";") ? null : expression(true);
20466 expect(";");
20467 var step = is("punc", ")") ? null : expression(true);
20468 expect(")");
20469 return new AST_For({
20470 init : init,
20471 condition : test,
20472 step : step,
20473 body : in_loop(statement)
20474 });
20475 };
20476
20477 function for_in(init) {
20478 var lhs = init instanceof AST_Var ? init.definitions[0].name : null;
20479 var obj = expression(true);
20480 expect(")");
20481 return new AST_ForIn({
20482 init : init,
20483 name : lhs,
20484 object : obj,
20485 body : in_loop(statement)
20486 });
20487 };
20488
20489 var function_ = function(ctor) {
20490 var in_statement = ctor === AST_Defun;
20491 var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
20492 if (in_statement && !name)
20493 unexpected();
20494 expect("(");
20495 return new ctor({
20496 name: name,
20497 argnames: (function(first, a){
20498 while (!is("punc", ")")) {
20499 if (first) first = false; else expect(",");
20500 a.push(as_symbol(AST_SymbolFunarg));
20501 }
20502 next();
20503 return a;
20504 })(true, []),
20505 body: (function(loop, labels){
20506 ++S.in_function;
20507 S.in_directives = true;
20508 S.in_loop = 0;
20509 S.labels = [];
20510 var a = block_();
20511 --S.in_function;
20512 S.in_loop = loop;
20513 S.labels = labels;
20514 return a;
20515 })(S.in_loop, S.labels)
20516 });
20517 };
20518
20519 function if_() {
20520 var cond = parenthesised(), body = statement(), belse = null;
20521 if (is("keyword", "else")) {
20522 next();
20523 belse = statement();
20524 }
20525 return new AST_If({
20526 condition : cond,
20527 body : body,
20528 alternative : belse
20529 });
20530 };
20531
20532 function block_() {
20533 expect("{");
20534 var a = [];
20535 while (!is("punc", "}")) {
20536 if (is("eof")) unexpected();
20537 a.push(statement());
20538 }
20539 next();
20540 return a;
20541 };
20542
20543 function switch_body_() {
20544 expect("{");
20545 var a = [], cur = null, branch = null, tmp;
20546 while (!is("punc", "}")) {
20547 if (is("eof")) unexpected();
20548 if (is("keyword", "case")) {
20549 if (branch) branch.end = prev();
20550 cur = [];
20551 branch = new AST_Case({
20552 start : (tmp = S.token, next(), tmp),
20553 expression : expression(true),
20554 body : cur
20555 });
20556 a.push(branch);
20557 expect(":");
20558 }
20559 else if (is("keyword", "default")) {
20560 if (branch) branch.end = prev();
20561 cur = [];
20562 branch = new AST_Default({
20563 start : (tmp = S.token, next(), expect(":"), tmp),
20564 body : cur
20565 });
20566 a.push(branch);
20567 }
20568 else {
20569 if (!cur) unexpected();
20570 cur.push(statement());
20571 }
20572 }
20573 if (branch) branch.end = prev();
20574 next();
20575 return a;
20576 };
20577
20578 function try_() {
20579 var body = block_(), bcatch = null, bfinally = null;
20580 if (is("keyword", "catch")) {
20581 var start = S.token;
20582 next();
20583 expect("(");
20584 var name = as_symbol(AST_SymbolCatch);
20585 expect(")");
20586 bcatch = new AST_Catch({
20587 start : start,
20588 argname : name,
20589 body : block_(),
20590 end : prev()
20591 });
20592 }
20593 if (is("keyword", "finally")) {
20594 var start = S.token;
20595 next();
20596 bfinally = new AST_Finally({
20597 start : start,
20598 body : block_(),
20599 end : prev()
20600 });
20601 }
20602 if (!bcatch && !bfinally)
20603 croak("Missing catch/finally blocks");
20604 return new AST_Try({
20605 body : body,
20606 bcatch : bcatch,
20607 bfinally : bfinally
20608 });
20609 };
20610
20611 function vardefs(no_in, in_const) {
20612 var a = [];
20613 for (;;) {
20614 a.push(new AST_VarDef({
20615 start : S.token,
20616 name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
20617 value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
20618 end : prev()
20619 }));
20620 if (!is("punc", ","))
20621 break;
20622 next();
20623 }
20624 return a;
20625 };
20626
20627 var var_ = function(no_in) {
20628 return new AST_Var({
20629 start : prev(),
20630 definitions : vardefs(no_in, false),
20631 end : prev()
20632 });
20633 };
20634
20635 var const_ = function() {
20636 return new AST_Const({
20637 start : prev(),
20638 definitions : vardefs(false, true),
20639 end : prev()
20640 });
20641 };
20642
20643 var new_ = function(allow_calls) {
20644 var start = S.token;
20645 expect_token("operator", "new");
20646 var newexp = expr_atom(false), args;
20647 if (is("punc", "(")) {
20648 next();
20649 args = expr_list(")");
20650 } else {
20651 args = [];
20652 }
20653 return subscripts(new AST_New({
20654 start : start,
20655 expression : newexp,
20656 args : args,
20657 end : prev()
20658 }), allow_calls);
20659 };
20660
20661 function as_atom_node() {
20662 var tok = S.token, ret;
20663 switch (tok.type) {
20664 case "name":
20665 case "keyword":
20666 ret = _make_symbol(AST_SymbolRef);
20667 break;
20668 case "num":
20669 ret = new AST_Number({ start: tok, end: tok, value: tok.value });
20670 break;
20671 case "string":
20672 ret = new AST_String({
20673 start : tok,
20674 end : tok,
20675 value : tok.value,
20676 quote : tok.quote
20677 });
20678 break;
20679 case "regexp":
20680 ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
20681 break;
20682 case "atom":
20683 switch (tok.value) {
20684 case "false":
20685 ret = new AST_False({ start: tok, end: tok });
20686 break;
20687 case "true":
20688 ret = new AST_True({ start: tok, end: tok });
20689 break;
20690 case "null":
20691 ret = new AST_Null({ start: tok, end: tok });
20692 break;
20693 }
20694 break;
20695 }
20696 next();
20697 return ret;
20698 };
20699
20700 var expr_atom = function(allow_calls) {
20701 if (is("operator", "new")) {
20702 return new_(allow_calls);
20703 }
20704 var start = S.token;
20705 if (is("punc")) {
20706 switch (start.value) {
20707 case "(":
20708 next();
20709 var ex = expression(true);
20710 ex.start = start;
20711 ex.end = S.token;
20712 expect(")");
20713 return subscripts(ex, allow_calls);
20714 case "[":
20715 return subscripts(array_(), allow_calls);
20716 case "{":
20717 return subscripts(object_(), allow_calls);
20718 }
20719 unexpected();
20720 }
20721 if (is("keyword", "function")) {
20722 next();
20723 var func = function_(AST_Function);
20724 func.start = start;
20725 func.end = prev();
20726 return subscripts(func, allow_calls);
20727 }
20728 if (ATOMIC_START_TOKEN[S.token.type]) {
20729 return subscripts(as_atom_node(), allow_calls);
20730 }
20731 unexpected();
20732 };
20733
20734 function expr_list(closing, allow_trailing_comma, allow_empty) {
20735 var first = true, a = [];
20736 while (!is("punc", closing)) {
20737 if (first) first = false; else expect(",");
20738 if (allow_trailing_comma && is("punc", closing)) break;
20739 if (is("punc", ",") && allow_empty) {
20740 a.push(new AST_Hole({ start: S.token, end: S.token }));
20741 } else {
20742 a.push(expression(false));
20743 }
20744 }
20745 next();
20746 return a;
20747 };
20748
20749 var array_ = embed_tokens(function() {
20750 expect("[");
20751 return new AST_Array({
20752 elements: expr_list("]", !options.strict, true)
20753 });
20754 });
20755
20756 var object_ = embed_tokens(function() {
20757 expect("{");
20758 var first = true, a = [];
20759 while (!is("punc", "}")) {
20760 if (first) first = false; else expect(",");
20761 if (!options.strict && is("punc", "}"))
20762 // allow trailing comma
20763 break;
20764 var start = S.token;
20765 var type = start.type;
20766 var name = as_property_name();
20767 if (type == "name" && !is("punc", ":")) {
20768 if (name == "get") {
20769 a.push(new AST_ObjectGetter({
20770 start : start,
20771 key : as_atom_node(),
20772 value : function_(AST_Accessor),
20773 end : prev()
20774 }));
20775 continue;
20776 }
20777 if (name == "set") {
20778 a.push(new AST_ObjectSetter({
20779 start : start,
20780 key : as_atom_node(),
20781 value : function_(AST_Accessor),
20782 end : prev()
20783 }));
20784 continue;
20785 }
20786 }
20787 expect(":");
20788 a.push(new AST_ObjectKeyVal({
20789 start : start,
20790 quote : start.quote,
20791 key : name,
20792 value : expression(false),
20793 end : prev()
20794 }));
20795 }
20796 next();
20797 return new AST_Object({ properties: a });
20798 });
20799
20800 function as_property_name() {
20801 var tmp = S.token;
20802 next();
20803 switch (tmp.type) {
20804 case "num":
20805 case "string":
20806 case "name":
20807 case "operator":
20808 case "keyword":
20809 case "atom":
20810 return tmp.value;
20811 default:
20812 unexpected();
20813 }
20814 };
20815
20816 function as_name() {
20817 var tmp = S.token;
20818 next();
20819 switch (tmp.type) {
20820 case "name":
20821 case "operator":
20822 case "keyword":
20823 case "atom":
20824 return tmp.value;
20825 default:
20826 unexpected();
20827 }
20828 };
20829
20830 function _make_symbol(type) {
20831 var name = S.token.value;
20832 return new (name == "this" ? AST_This : type)({
20833 name : String(name),
20834 start : S.token,
20835 end : S.token
20836 });
20837 };
20838
20839 function as_symbol(type, noerror) {
20840 if (!is("name")) {
20841 if (!noerror) croak("Name expected");
20842 return null;
20843 }
20844 var sym = _make_symbol(type);
20845 next();
20846 return sym;
20847 };
20848
20849 var subscripts = function(expr, allow_calls) {
20850 var start = expr.start;
20851 if (is("punc", ".")) {
20852 next();
20853 return subscripts(new AST_Dot({
20854 start : start,
20855 expression : expr,
20856 property : as_name(),
20857 end : prev()
20858 }), allow_calls);
20859 }
20860 if (is("punc", "[")) {
20861 next();
20862 var prop = expression(true);
20863 expect("]");
20864 return subscripts(new AST_Sub({
20865 start : start,
20866 expression : expr,
20867 property : prop,
20868 end : prev()
20869 }), allow_calls);
20870 }
20871 if (allow_calls && is("punc", "(")) {
20872 next();
20873 return subscripts(new AST_Call({
20874 start : start,
20875 expression : expr,
20876 args : expr_list(")"),
20877 end : prev()
20878 }), true);
20879 }
20880 return expr;
20881 };
20882
20883 var maybe_unary = function(allow_calls) {
20884 var start = S.token;
20885 if (is("operator") && UNARY_PREFIX(start.value)) {
20886 next();
20887 handle_regexp();
20888 var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
20889 ex.start = start;
20890 ex.end = prev();
20891 return ex;
20892 }
20893 var val = expr_atom(allow_calls);
20894 while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
20895 val = make_unary(AST_UnaryPostfix, S.token.value, val);
20896 val.start = start;
20897 val.end = S.token;
20898 next();
20899 }
20900 return val;
20901 };
20902
20903 function make_unary(ctor, op, expr) {
20904 if ((op == "++" || op == "--") && !is_assignable(expr))
20905 croak("Invalid use of " + op + " operator");
20906 return new ctor({ operator: op, expression: expr });
20907 };
20908
20909 var expr_op = function(left, min_prec, no_in) {
20910 var op = is("operator") ? S.token.value : null;
20911 if (op == "in" && no_in) op = null;
20912 var prec = op != null ? PRECEDENCE[op] : null;
20913 if (prec != null && prec > min_prec) {
20914 next();
20915 var right = expr_op(maybe_unary(true), prec, no_in);
20916 return expr_op(new AST_Binary({
20917 start : left.start,
20918 left : left,
20919 operator : op,
20920 right : right,
20921 end : right.end
20922 }), min_prec, no_in);
20923 }
20924 return left;
20925 };
20926
20927 function expr_ops(no_in) {
20928 return expr_op(maybe_unary(true), 0, no_in);
20929 };
20930
20931 var maybe_conditional = function(no_in) {
20932 var start = S.token;
20933 var expr = expr_ops(no_in);
20934 if (is("operator", "?")) {
20935 next();
20936 var yes = expression(false);
20937 expect(":");
20938 return new AST_Conditional({
20939 start : start,
20940 condition : expr,
20941 consequent : yes,
20942 alternative : expression(false, no_in),
20943 end : prev()
20944 });
20945 }
20946 return expr;
20947 };
20948
20949 function is_assignable(expr) {
20950 if (!options.strict) return true;
20951 if (expr instanceof AST_This) return false;
20952 return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
20953 };
20954
20955 var maybe_assign = function(no_in) {
20956 var start = S.token;
20957 var left = maybe_conditional(no_in), val = S.token.value;
20958 if (is("operator") && ASSIGNMENT(val)) {
20959 if (is_assignable(left)) {
20960 next();
20961 return new AST_Assign({
20962 start : start,
20963 left : left,
20964 operator : val,
20965 right : maybe_assign(no_in),
20966 end : prev()
20967 });
20968 }
20969 croak("Invalid assignment");
20970 }
20971 return left;
20972 };
20973
20974 var expression = function(commas, no_in) {
20975 var start = S.token;
20976 var expr = maybe_assign(no_in);
20977 if (commas && is("punc", ",")) {
20978 next();
20979 return new AST_Seq({
20980 start : start,
20981 car : expr,
20982 cdr : expression(true, no_in),
20983 end : peek()
20984 });
20985 }
20986 return expr;
20987 };
20988
20989 function in_loop(cont) {
20990 ++S.in_loop;
20991 var ret = cont();
20992 --S.in_loop;
20993 return ret;
20994 };
20995
20996 if (options.expression) {
20997 return expression(true);
20998 }
20999
21000 return (function(){
21001 var start = S.token;
21002 var body = [];
21003 while (!is("eof"))
21004 body.push(statement());
21005 var end = prev();
21006 var toplevel = options.toplevel;
21007 if (toplevel) {
21008 toplevel.body = toplevel.body.concat(body);
21009 toplevel.end = end;
21010 } else {
21011 toplevel = new AST_Toplevel({ start: start, body: body, end: end });
21012 }
21013 return toplevel;
21014 })();
21015
21016};
21017
21018/***********************************************************************
21019
21020 A JavaScript tokenizer / parser / beautifier / compressor.
21021 https://github.com/mishoo/UglifyJS2
21022
21023 -------------------------------- (C) ---------------------------------
21024
21025 Author: Mihai Bazon
21026 <mihai.bazon@gmail.com>
21027 http://mihai.bazon.net/blog
21028
21029 Distributed under the BSD license:
21030
21031 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
21032
21033 Redistribution and use in source and binary forms, with or without
21034 modification, are permitted provided that the following conditions
21035 are met:
21036
21037 * Redistributions of source code must retain the above
21038 copyright notice, this list of conditions and the following
21039 disclaimer.
21040
21041 * Redistributions in binary form must reproduce the above
21042 copyright notice, this list of conditions and the following
21043 disclaimer in the documentation and/or other materials
21044 provided with the distribution.
21045
21046 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
21047 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21048 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21049 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21050 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21051 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21052 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21053 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21054 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
21055 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
21056 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21057 SUCH DAMAGE.
21058
21059 ***********************************************************************/
21060
21061"use strict";
21062
21063// Tree transformer helpers.
21064
21065function TreeTransformer(before, after) {
21066 TreeWalker.call(this);
21067 this.before = before;
21068 this.after = after;
21069}
21070TreeTransformer.prototype = new TreeWalker;
21071
21072(function(undefined){
21073
21074 function _(node, descend) {
21075 node.DEFMETHOD("transform", function(tw, in_list){
21076 var x, y;
21077 tw.push(this);
21078 if (tw.before) x = tw.before(this, descend, in_list);
21079 if (x === undefined) {
21080 if (!tw.after) {
21081 x = this;
21082 descend(x, tw);
21083 } else {
21084 tw.stack[tw.stack.length - 1] = x = this.clone();
21085 descend(x, tw);
21086 y = tw.after(x, in_list);
21087 if (y !== undefined) x = y;
21088 }
21089 }
21090 tw.pop(this);
21091 return x;
21092 });
21093 };
21094
21095 function do_list(list, tw) {
21096 return MAP(list, function(node){
21097 return node.transform(tw, true);
21098 });
21099 };
21100
21101 _(AST_Node, noop);
21102
21103 _(AST_LabeledStatement, function(self, tw){
21104 self.label = self.label.transform(tw);
21105 self.body = self.body.transform(tw);
21106 });
21107
21108 _(AST_SimpleStatement, function(self, tw){
21109 self.body = self.body.transform(tw);
21110 });
21111
21112 _(AST_Block, function(self, tw){
21113 self.body = do_list(self.body, tw);
21114 });
21115
21116 _(AST_DWLoop, function(self, tw){
21117 self.condition = self.condition.transform(tw);
21118 self.body = self.body.transform(tw);
21119 });
21120
21121 _(AST_For, function(self, tw){
21122 if (self.init) self.init = self.init.transform(tw);
21123 if (self.condition) self.condition = self.condition.transform(tw);
21124 if (self.step) self.step = self.step.transform(tw);
21125 self.body = self.body.transform(tw);
21126 });
21127
21128 _(AST_ForIn, function(self, tw){
21129 self.init = self.init.transform(tw);
21130 self.object = self.object.transform(tw);
21131 self.body = self.body.transform(tw);
21132 });
21133
21134 _(AST_With, function(self, tw){
21135 self.expression = self.expression.transform(tw);
21136 self.body = self.body.transform(tw);
21137 });
21138
21139 _(AST_Exit, function(self, tw){
21140 if (self.value) self.value = self.value.transform(tw);
21141 });
21142
21143 _(AST_LoopControl, function(self, tw){
21144 if (self.label) self.label = self.label.transform(tw);
21145 });
21146
21147 _(AST_If, function(self, tw){
21148 self.condition = self.condition.transform(tw);
21149 self.body = self.body.transform(tw);
21150 if (self.alternative) self.alternative = self.alternative.transform(tw);
21151 });
21152
21153 _(AST_Switch, function(self, tw){
21154 self.expression = self.expression.transform(tw);
21155 self.body = do_list(self.body, tw);
21156 });
21157
21158 _(AST_Case, function(self, tw){
21159 self.expression = self.expression.transform(tw);
21160 self.body = do_list(self.body, tw);
21161 });
21162
21163 _(AST_Try, function(self, tw){
21164 self.body = do_list(self.body, tw);
21165 if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
21166 if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
21167 });
21168
21169 _(AST_Catch, function(self, tw){
21170 self.argname = self.argname.transform(tw);
21171 self.body = do_list(self.body, tw);
21172 });
21173
21174 _(AST_Definitions, function(self, tw){
21175 self.definitions = do_list(self.definitions, tw);
21176 });
21177
21178 _(AST_VarDef, function(self, tw){
21179 self.name = self.name.transform(tw);
21180 if (self.value) self.value = self.value.transform(tw);
21181 });
21182
21183 _(AST_Lambda, function(self, tw){
21184 if (self.name) self.name = self.name.transform(tw);
21185 self.argnames = do_list(self.argnames, tw);
21186 self.body = do_list(self.body, tw);
21187 });
21188
21189 _(AST_Call, function(self, tw){
21190 self.expression = self.expression.transform(tw);
21191 self.args = do_list(self.args, tw);
21192 });
21193
21194 _(AST_Seq, function(self, tw){
21195 self.car = self.car.transform(tw);
21196 self.cdr = self.cdr.transform(tw);
21197 });
21198
21199 _(AST_Dot, function(self, tw){
21200 self.expression = self.expression.transform(tw);
21201 });
21202
21203 _(AST_Sub, function(self, tw){
21204 self.expression = self.expression.transform(tw);
21205 self.property = self.property.transform(tw);
21206 });
21207
21208 _(AST_Unary, function(self, tw){
21209 self.expression = self.expression.transform(tw);
21210 });
21211
21212 _(AST_Binary, function(self, tw){
21213 self.left = self.left.transform(tw);
21214 self.right = self.right.transform(tw);
21215 });
21216
21217 _(AST_Conditional, function(self, tw){
21218 self.condition = self.condition.transform(tw);
21219 self.consequent = self.consequent.transform(tw);
21220 self.alternative = self.alternative.transform(tw);
21221 });
21222
21223 _(AST_Array, function(self, tw){
21224 self.elements = do_list(self.elements, tw);
21225 });
21226
21227 _(AST_Object, function(self, tw){
21228 self.properties = do_list(self.properties, tw);
21229 });
21230
21231 _(AST_ObjectProperty, function(self, tw){
21232 self.value = self.value.transform(tw);
21233 });
21234
21235})();
21236
21237/***********************************************************************
21238
21239 A JavaScript tokenizer / parser / beautifier / compressor.
21240 https://github.com/mishoo/UglifyJS2
21241
21242 -------------------------------- (C) ---------------------------------
21243
21244 Author: Mihai Bazon
21245 <mihai.bazon@gmail.com>
21246 http://mihai.bazon.net/blog
21247
21248 Distributed under the BSD license:
21249
21250 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
21251
21252 Redistribution and use in source and binary forms, with or without
21253 modification, are permitted provided that the following conditions
21254 are met:
21255
21256 * Redistributions of source code must retain the above
21257 copyright notice, this list of conditions and the following
21258 disclaimer.
21259
21260 * Redistributions in binary form must reproduce the above
21261 copyright notice, this list of conditions and the following
21262 disclaimer in the documentation and/or other materials
21263 provided with the distribution.
21264
21265 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
21266 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21267 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21268 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21269 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21270 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21271 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21272 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21273 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
21274 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
21275 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21276 SUCH DAMAGE.
21277
21278 ***********************************************************************/
21279
21280"use strict";
21281
21282function SymbolDef(scope, index, orig) {
21283 this.name = orig.name;
21284 this.orig = [ orig ];
21285 this.scope = scope;
21286 this.references = [];
21287 this.global = false;
21288 this.mangled_name = null;
21289 this.undeclared = false;
21290 this.constant = false;
21291 this.index = index;
21292};
21293
21294SymbolDef.prototype = {
21295 unmangleable: function(options) {
21296 if (!options) options = {};
21297
21298 return (this.global && !options.toplevel)
21299 || this.undeclared
21300 || (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
21301 || (options.keep_fnames
21302 && (this.orig[0] instanceof AST_SymbolLambda
21303 || this.orig[0] instanceof AST_SymbolDefun));
21304 },
21305 mangle: function(options) {
21306 var cache = options.cache && options.cache.props;
21307 if (this.global && cache && cache.has(this.name)) {
21308 this.mangled_name = cache.get(this.name);
21309 }
21310 else if (!this.mangled_name && !this.unmangleable(options)) {
21311 var s = this.scope;
21312 if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
21313 s = s.parent_scope;
21314 this.mangled_name = s.next_mangled(options, this);
21315 if (this.global && cache) {
21316 cache.set(this.name, this.mangled_name);
21317 }
21318 }
21319 }
21320};
21321
21322AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
21323 options = defaults(options, {
21324 screw_ie8: false,
21325 cache: null
21326 });
21327
21328 // pass 1: setup scope chaining and handle definitions
21329 var self = this;
21330 var scope = self.parent_scope = null;
21331 var labels = new Dictionary();
21332 var defun = null;
21333 var nesting = 0;
21334 var tw = new TreeWalker(function(node, descend){
21335 if (options.screw_ie8 && node instanceof AST_Catch) {
21336 var save_scope = scope;
21337 scope = new AST_Scope(node);
21338 scope.init_scope_vars(nesting);
21339 scope.parent_scope = save_scope;
21340 descend();
21341 scope = save_scope;
21342 return true;
21343 }
21344 if (node instanceof AST_Scope) {
21345 node.init_scope_vars(nesting);
21346 var save_scope = node.parent_scope = scope;
21347 var save_defun = defun;
21348 var save_labels = labels;
21349 defun = scope = node;
21350 labels = new Dictionary();
21351 ++nesting; descend(); --nesting;
21352 scope = save_scope;
21353 defun = save_defun;
21354 labels = save_labels;
21355 return true; // don't descend again in TreeWalker
21356 }
21357 if (node instanceof AST_LabeledStatement) {
21358 var l = node.label;
21359 if (labels.has(l.name)) {
21360 throw new Error(string_template("Label {name} defined twice", l));
21361 }
21362 labels.set(l.name, l);
21363 descend();
21364 labels.del(l.name);
21365 return true; // no descend again
21366 }
21367 if (node instanceof AST_With) {
21368 for (var s = scope; s; s = s.parent_scope)
21369 s.uses_with = true;
21370 return;
21371 }
21372 if (node instanceof AST_Symbol) {
21373 node.scope = scope;
21374 }
21375 if (node instanceof AST_Label) {
21376 node.thedef = node;
21377 node.references = [];
21378 }
21379 if (node instanceof AST_SymbolLambda) {
21380 defun.def_function(node);
21381 }
21382 else if (node instanceof AST_SymbolDefun) {
21383 // Careful here, the scope where this should be defined is
21384 // the parent scope. The reason is that we enter a new
21385 // scope when we encounter the AST_Defun node (which is
21386 // instanceof AST_Scope) but we get to the symbol a bit
21387 // later.
21388 (node.scope = defun.parent_scope).def_function(node);
21389 }
21390 else if (node instanceof AST_SymbolVar
21391 || node instanceof AST_SymbolConst) {
21392 var def = defun.def_variable(node);
21393 def.constant = node instanceof AST_SymbolConst;
21394 def.init = tw.parent().value;
21395 }
21396 else if (node instanceof AST_SymbolCatch) {
21397 (options.screw_ie8 ? scope : defun)
21398 .def_variable(node);
21399 }
21400 else if (node instanceof AST_LabelRef) {
21401 var sym = labels.get(node.name);
21402 if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
21403 name: node.name,
21404 line: node.start.line,
21405 col: node.start.col
21406 }));
21407 node.thedef = sym;
21408 }
21409 });
21410 self.walk(tw);
21411
21412 // pass 2: find back references and eval
21413 var func = null;
21414 var globals = self.globals = new Dictionary();
21415 var tw = new TreeWalker(function(node, descend){
21416 if (node instanceof AST_Lambda) {
21417 var prev_func = func;
21418 func = node;
21419 descend();
21420 func = prev_func;
21421 return true;
21422 }
21423 if (node instanceof AST_LoopControl && node.label) {
21424 node.label.thedef.references.push(node);
21425 return true;
21426 }
21427 if (node instanceof AST_SymbolRef) {
21428 var name = node.name;
21429 var sym = node.scope.find_variable(name);
21430 if (!sym) {
21431 var g;
21432 if (globals.has(name)) {
21433 g = globals.get(name);
21434 } else {
21435 g = new SymbolDef(self, globals.size(), node);
21436 g.undeclared = true;
21437 g.global = true;
21438 globals.set(name, g);
21439 }
21440 node.thedef = g;
21441 if (name == "eval" && tw.parent() instanceof AST_Call) {
21442 for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
21443 s.uses_eval = true;
21444 }
21445 if (func && name == "arguments") {
21446 func.uses_arguments = true;
21447 }
21448 } else {
21449 node.thedef = sym;
21450 }
21451 node.reference();
21452 return true;
21453 }
21454 });
21455 self.walk(tw);
21456
21457 if (options.cache) {
21458 this.cname = options.cache.cname;
21459 }
21460});
21461
21462AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
21463 this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
21464 this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
21465 this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
21466 this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
21467 this.parent_scope = null; // the parent scope
21468 this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
21469 this.cname = -1; // the current index for mangling functions/variables
21470 this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
21471});
21472
21473AST_Lambda.DEFMETHOD("init_scope_vars", function(){
21474 AST_Scope.prototype.init_scope_vars.apply(this, arguments);
21475 this.uses_arguments = false;
21476});
21477
21478AST_SymbolRef.DEFMETHOD("reference", function() {
21479 var def = this.definition();
21480 def.references.push(this);
21481 var s = this.scope;
21482 while (s) {
21483 push_uniq(s.enclosed, def);
21484 if (s === def.scope) break;
21485 s = s.parent_scope;
21486 }
21487 this.frame = this.scope.nesting - def.scope.nesting;
21488});
21489
21490AST_Scope.DEFMETHOD("find_variable", function(name){
21491 if (name instanceof AST_Symbol) name = name.name;
21492 return this.variables.get(name)
21493 || (this.parent_scope && this.parent_scope.find_variable(name));
21494});
21495
21496AST_Scope.DEFMETHOD("def_function", function(symbol){
21497 this.functions.set(symbol.name, this.def_variable(symbol));
21498});
21499
21500AST_Scope.DEFMETHOD("def_variable", function(symbol){
21501 var def;
21502 if (!this.variables.has(symbol.name)) {
21503 def = new SymbolDef(this, this.variables.size(), symbol);
21504 this.variables.set(symbol.name, def);
21505 def.global = !this.parent_scope;
21506 } else {
21507 def = this.variables.get(symbol.name);
21508 def.orig.push(symbol);
21509 }
21510 return symbol.thedef = def;
21511});
21512
21513AST_Scope.DEFMETHOD("next_mangled", function(options){
21514 var ext = this.enclosed;
21515 out: while (true) {
21516 var m = base54(++this.cname);
21517 if (!is_identifier(m)) continue; // skip over "do"
21518
21519 // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
21520 // shadow a name excepted from mangling.
21521 if (options.except.indexOf(m) >= 0) continue;
21522
21523 // we must ensure that the mangled name does not shadow a name
21524 // from some parent scope that is referenced in this or in
21525 // inner scopes.
21526 for (var i = ext.length; --i >= 0;) {
21527 var sym = ext[i];
21528 var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
21529 if (m == name) continue out;
21530 }
21531 return m;
21532 }
21533});
21534
21535AST_Function.DEFMETHOD("next_mangled", function(options, def){
21536 // #179, #326
21537 // in Safari strict mode, something like (function x(x){...}) is a syntax error;
21538 // a function expression's argument cannot shadow the function expression's name
21539
21540 var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
21541 while (true) {
21542 var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
21543 if (!(tricky_def && tricky_def.mangled_name == name))
21544 return name;
21545 }
21546});
21547
21548AST_Scope.DEFMETHOD("references", function(sym){
21549 if (sym instanceof AST_Symbol) sym = sym.definition();
21550 return this.enclosed.indexOf(sym) < 0 ? null : sym;
21551});
21552
21553AST_Symbol.DEFMETHOD("unmangleable", function(options){
21554 return this.definition().unmangleable(options);
21555});
21556
21557// property accessors are not mangleable
21558AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
21559 return true;
21560});
21561
21562// labels are always mangleable
21563AST_Label.DEFMETHOD("unmangleable", function(){
21564 return false;
21565});
21566
21567AST_Symbol.DEFMETHOD("unreferenced", function(){
21568 return this.definition().references.length == 0
21569 && !(this.scope.uses_eval || this.scope.uses_with);
21570});
21571
21572AST_Symbol.DEFMETHOD("undeclared", function(){
21573 return this.definition().undeclared;
21574});
21575
21576AST_LabelRef.DEFMETHOD("undeclared", function(){
21577 return false;
21578});
21579
21580AST_Label.DEFMETHOD("undeclared", function(){
21581 return false;
21582});
21583
21584AST_Symbol.DEFMETHOD("definition", function(){
21585 return this.thedef;
21586});
21587
21588AST_Symbol.DEFMETHOD("global", function(){
21589 return this.definition().global;
21590});
21591
21592AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
21593 return defaults(options, {
21594 except : [],
21595 eval : false,
21596 sort : false,
21597 toplevel : false,
21598 screw_ie8 : false,
21599 keep_fnames : false
21600 });
21601});
21602
21603AST_Toplevel.DEFMETHOD("mangle_names", function(options){
21604 options = this._default_mangler_options(options);
21605 // We only need to mangle declaration nodes. Special logic wired
21606 // into the code generator will display the mangled name if it's
21607 // present (and for AST_SymbolRef-s it'll use the mangled name of
21608 // the AST_SymbolDeclaration that it points to).
21609 var lname = -1;
21610 var to_mangle = [];
21611
21612 if (options.cache) {
21613 this.globals.each(function(symbol){
21614 if (options.except.indexOf(symbol.name) < 0) {
21615 to_mangle.push(symbol);
21616 }
21617 });
21618 }
21619
21620 var tw = new TreeWalker(function(node, descend){
21621 if (node instanceof AST_LabeledStatement) {
21622 // lname is incremented when we get to the AST_Label
21623 var save_nesting = lname;
21624 descend();
21625 lname = save_nesting;
21626 return true; // don't descend again in TreeWalker
21627 }
21628 if (node instanceof AST_Scope) {
21629 var p = tw.parent(), a = [];
21630 node.variables.each(function(symbol){
21631 if (options.except.indexOf(symbol.name) < 0) {
21632 a.push(symbol);
21633 }
21634 });
21635 if (options.sort) a.sort(function(a, b){
21636 return b.references.length - a.references.length;
21637 });
21638 to_mangle.push.apply(to_mangle, a);
21639 return;
21640 }
21641 if (node instanceof AST_Label) {
21642 var name;
21643 do name = base54(++lname); while (!is_identifier(name));
21644 node.mangled_name = name;
21645 return true;
21646 }
21647 if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
21648 to_mangle.push(node.definition());
21649 return;
21650 }
21651 });
21652 this.walk(tw);
21653 to_mangle.forEach(function(def){ def.mangle(options) });
21654
21655 if (options.cache) {
21656 options.cache.cname = this.cname;
21657 }
21658});
21659
21660AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
21661 options = this._default_mangler_options(options);
21662 var tw = new TreeWalker(function(node){
21663 if (node instanceof AST_Constant)
21664 base54.consider(node.print_to_string());
21665 else if (node instanceof AST_Return)
21666 base54.consider("return");
21667 else if (node instanceof AST_Throw)
21668 base54.consider("throw");
21669 else if (node instanceof AST_Continue)
21670 base54.consider("continue");
21671 else if (node instanceof AST_Break)
21672 base54.consider("break");
21673 else if (node instanceof AST_Debugger)
21674 base54.consider("debugger");
21675 else if (node instanceof AST_Directive)
21676 base54.consider(node.value);
21677 else if (node instanceof AST_While)
21678 base54.consider("while");
21679 else if (node instanceof AST_Do)
21680 base54.consider("do while");
21681 else if (node instanceof AST_If) {
21682 base54.consider("if");
21683 if (node.alternative) base54.consider("else");
21684 }
21685 else if (node instanceof AST_Var)
21686 base54.consider("var");
21687 else if (node instanceof AST_Const)
21688 base54.consider("const");
21689 else if (node instanceof AST_Lambda)
21690 base54.consider("function");
21691 else if (node instanceof AST_For)
21692 base54.consider("for");
21693 else if (node instanceof AST_ForIn)
21694 base54.consider("for in");
21695 else if (node instanceof AST_Switch)
21696 base54.consider("switch");
21697 else if (node instanceof AST_Case)
21698 base54.consider("case");
21699 else if (node instanceof AST_Default)
21700 base54.consider("default");
21701 else if (node instanceof AST_With)
21702 base54.consider("with");
21703 else if (node instanceof AST_ObjectSetter)
21704 base54.consider("set" + node.key);
21705 else if (node instanceof AST_ObjectGetter)
21706 base54.consider("get" + node.key);
21707 else if (node instanceof AST_ObjectKeyVal)
21708 base54.consider(node.key);
21709 else if (node instanceof AST_New)
21710 base54.consider("new");
21711 else if (node instanceof AST_This)
21712 base54.consider("this");
21713 else if (node instanceof AST_Try)
21714 base54.consider("try");
21715 else if (node instanceof AST_Catch)
21716 base54.consider("catch");
21717 else if (node instanceof AST_Finally)
21718 base54.consider("finally");
21719 else if (node instanceof AST_Symbol && node.unmangleable(options))
21720 base54.consider(node.name);
21721 else if (node instanceof AST_Unary || node instanceof AST_Binary)
21722 base54.consider(node.operator);
21723 else if (node instanceof AST_Dot)
21724 base54.consider(node.property);
21725 });
21726 this.walk(tw);
21727 base54.sort();
21728});
21729
21730var base54 = (function() {
21731 var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
21732 var chars, frequency;
21733 function reset() {
21734 frequency = Object.create(null);
21735 chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
21736 chars.forEach(function(ch){ frequency[ch] = 0 });
21737 }
21738 base54.consider = function(str){
21739 for (var i = str.length; --i >= 0;) {
21740 var code = str.charCodeAt(i);
21741 if (code in frequency) ++frequency[code];
21742 }
21743 };
21744 base54.sort = function() {
21745 chars = mergeSort(chars, function(a, b){
21746 if (is_digit(a) && !is_digit(b)) return 1;
21747 if (is_digit(b) && !is_digit(a)) return -1;
21748 return frequency[b] - frequency[a];
21749 });
21750 };
21751 base54.reset = reset;
21752 reset();
21753 base54.get = function(){ return chars };
21754 base54.freq = function(){ return frequency };
21755 function base54(num) {
21756 var ret = "", base = 54;
21757 num++;
21758 do {
21759 num--;
21760 ret += String.fromCharCode(chars[num % base]);
21761 num = Math.floor(num / base);
21762 base = 64;
21763 } while (num > 0);
21764 return ret;
21765 };
21766 return base54;
21767})();
21768
21769AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
21770 options = defaults(options, {
21771 undeclared : false, // this makes a lot of noise
21772 unreferenced : true,
21773 assign_to_global : true,
21774 func_arguments : true,
21775 nested_defuns : true,
21776 eval : true
21777 });
21778 var tw = new TreeWalker(function(node){
21779 if (options.undeclared
21780 && node instanceof AST_SymbolRef
21781 && node.undeclared())
21782 {
21783 // XXX: this also warns about JS standard names,
21784 // i.e. Object, Array, parseInt etc. Should add a list of
21785 // exceptions.
21786 AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
21787 name: node.name,
21788 file: node.start.file,
21789 line: node.start.line,
21790 col: node.start.col
21791 });
21792 }
21793 if (options.assign_to_global)
21794 {
21795 var sym = null;
21796 if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef)
21797 sym = node.left;
21798 else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef)
21799 sym = node.init;
21800 if (sym
21801 && (sym.undeclared()
21802 || (sym.global() && sym.scope !== sym.definition().scope))) {
21803 AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
21804 msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
21805 name: sym.name,
21806 file: sym.start.file,
21807 line: sym.start.line,
21808 col: sym.start.col
21809 });
21810 }
21811 }
21812 if (options.eval
21813 && node instanceof AST_SymbolRef
21814 && node.undeclared()
21815 && node.name == "eval") {
21816 AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
21817 }
21818 if (options.unreferenced
21819 && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
21820 && !(node instanceof AST_SymbolCatch)
21821 && node.unreferenced()) {
21822 AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
21823 type: node instanceof AST_Label ? "Label" : "Symbol",
21824 name: node.name,
21825 file: node.start.file,
21826 line: node.start.line,
21827 col: node.start.col
21828 });
21829 }
21830 if (options.func_arguments
21831 && node instanceof AST_Lambda
21832 && node.uses_arguments) {
21833 AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
21834 name: node.name ? node.name.name : "anonymous",
21835 file: node.start.file,
21836 line: node.start.line,
21837 col: node.start.col
21838 });
21839 }
21840 if (options.nested_defuns
21841 && node instanceof AST_Defun
21842 && !(tw.parent() instanceof AST_Scope)) {
21843 AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", {
21844 name: node.name.name,
21845 type: tw.parent().TYPE,
21846 file: node.start.file,
21847 line: node.start.line,
21848 col: node.start.col
21849 });
21850 }
21851 });
21852 this.walk(tw);
21853});
21854
21855/***********************************************************************
21856
21857 A JavaScript tokenizer / parser / beautifier / compressor.
21858 https://github.com/mishoo/UglifyJS2
21859
21860 -------------------------------- (C) ---------------------------------
21861
21862 Author: Mihai Bazon
21863 <mihai.bazon@gmail.com>
21864 http://mihai.bazon.net/blog
21865
21866 Distributed under the BSD license:
21867
21868 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
21869
21870 Redistribution and use in source and binary forms, with or without
21871 modification, are permitted provided that the following conditions
21872 are met:
21873
21874 * Redistributions of source code must retain the above
21875 copyright notice, this list of conditions and the following
21876 disclaimer.
21877
21878 * Redistributions in binary form must reproduce the above
21879 copyright notice, this list of conditions and the following
21880 disclaimer in the documentation and/or other materials
21881 provided with the distribution.
21882
21883 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
21884 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21885 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21886 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21887 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21888 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21889 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21890 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21891 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
21892 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
21893 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21894 SUCH DAMAGE.
21895
21896 ***********************************************************************/
21897
21898"use strict";
21899
21900function OutputStream(options) {
21901
21902 options = defaults(options, {
21903 indent_start : 0,
21904 indent_level : 4,
21905 quote_keys : false,
21906 space_colon : true,
21907 ascii_only : false,
21908 unescape_regexps : false,
21909 inline_script : false,
21910 width : 80,
21911 max_line_len : 32000,
21912 beautify : false,
21913 source_map : null,
21914 bracketize : false,
21915 semicolons : true,
21916 comments : false,
21917 shebang : true,
21918 preserve_line : false,
21919 screw_ie8 : false,
21920 preamble : null,
21921 quote_style : 0
21922 }, true);
21923
21924 var indentation = 0;
21925 var current_col = 0;
21926 var current_line = 1;
21927 var current_pos = 0;
21928 var OUTPUT = "";
21929
21930 function to_ascii(str, identifier) {
21931 return str.replace(/[\u0080-\uffff]/g, function(ch) {
21932 var code = ch.charCodeAt(0).toString(16);
21933 if (code.length <= 2 && !identifier) {
21934 while (code.length < 2) code = "0" + code;
21935 return "\\x" + code;
21936 } else {
21937 while (code.length < 4) code = "0" + code;
21938 return "\\u" + code;
21939 }
21940 });
21941 };
21942
21943 function make_string(str, quote) {
21944 var dq = 0, sq = 0;
21945 str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s){
21946 switch (s) {
21947 case "\\": return "\\\\";
21948 case "\b": return "\\b";
21949 case "\f": return "\\f";
21950 case "\n": return "\\n";
21951 case "\r": return "\\r";
21952 case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B";
21953 case "\u2028": return "\\u2028";
21954 case "\u2029": return "\\u2029";
21955 case '"': ++dq; return '"';
21956 case "'": ++sq; return "'";
21957 case "\0": return "\\x00";
21958 case "\ufeff": return "\\ufeff";
21959 }
21960 return s;
21961 });
21962 function quote_single() {
21963 return "'" + str.replace(/\x27/g, "\\'") + "'";
21964 }
21965 function quote_double() {
21966 return '"' + str.replace(/\x22/g, '\\"') + '"';
21967 }
21968 if (options.ascii_only) str = to_ascii(str);
21969 switch (options.quote_style) {
21970 case 1:
21971 return quote_single();
21972 case 2:
21973 return quote_double();
21974 case 3:
21975 return quote == "'" ? quote_single() : quote_double();
21976 default:
21977 return dq > sq ? quote_single() : quote_double();
21978 }
21979 };
21980
21981 function encode_string(str, quote) {
21982 var ret = make_string(str, quote);
21983 if (options.inline_script) {
21984 ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
21985 ret = ret.replace(/\x3c!--/g, "\\x3c!--");
21986 ret = ret.replace(/--\x3e/g, "--\\x3e");
21987 }
21988 return ret;
21989 };
21990
21991 function make_name(name) {
21992 name = name.toString();
21993 if (options.ascii_only)
21994 name = to_ascii(name, true);
21995 return name;
21996 };
21997
21998 function make_indent(back) {
21999 return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
22000 };
22001
22002 /* -----[ beautification/minification ]----- */
22003
22004 var might_need_space = false;
22005 var might_need_semicolon = false;
22006 var last = null;
22007
22008 function last_char() {
22009 return last.charAt(last.length - 1);
22010 };
22011
22012 function maybe_newline() {
22013 if (options.max_line_len && current_col > options.max_line_len)
22014 print("\n");
22015 };
22016
22017 var requireSemicolonChars = makePredicate("( [ + * / - , .");
22018
22019 function print(str) {
22020 str = String(str);
22021 var ch = str.charAt(0);
22022 if (might_need_semicolon) {
22023 might_need_semicolon = false;
22024
22025 if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
22026 if (options.semicolons || requireSemicolonChars(ch)) {
22027 OUTPUT += ";";
22028 current_col++;
22029 current_pos++;
22030 } else {
22031 OUTPUT += "\n";
22032 current_pos++;
22033 current_line++;
22034 current_col = 0;
22035
22036 if (/^\s+$/.test(str)) {
22037 // reset the semicolon flag, since we didn't print one
22038 // now and might still have to later
22039 might_need_semicolon = true;
22040 }
22041 }
22042
22043 if (!options.beautify)
22044 might_need_space = false;
22045 }
22046 }
22047
22048 if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
22049 var target_line = stack[stack.length - 1].start.line;
22050 while (current_line < target_line) {
22051 OUTPUT += "\n";
22052 current_pos++;
22053 current_line++;
22054 current_col = 0;
22055 might_need_space = false;
22056 }
22057 }
22058
22059 if (might_need_space) {
22060 var prev = last_char();
22061 if ((is_identifier_char(prev)
22062 && (is_identifier_char(ch) || ch == "\\"))
22063 || (/^[\+\-\/]$/.test(ch) && ch == prev))
22064 {
22065 OUTPUT += " ";
22066 current_col++;
22067 current_pos++;
22068 }
22069 might_need_space = false;
22070 }
22071 var a = str.split(/\r?\n/), n = a.length - 1;
22072 current_line += n;
22073 if (n == 0) {
22074 current_col += a[n].length;
22075 } else {
22076 current_col = a[n].length;
22077 }
22078 current_pos += str.length;
22079 last = str;
22080 OUTPUT += str;
22081 };
22082
22083 var space = options.beautify ? function() {
22084 print(" ");
22085 } : function() {
22086 might_need_space = true;
22087 };
22088
22089 var indent = options.beautify ? function(half) {
22090 if (options.beautify) {
22091 print(make_indent(half ? 0.5 : 0));
22092 }
22093 } : noop;
22094
22095 var with_indent = options.beautify ? function(col, cont) {
22096 if (col === true) col = next_indent();
22097 var save_indentation = indentation;
22098 indentation = col;
22099 var ret = cont();
22100 indentation = save_indentation;
22101 return ret;
22102 } : function(col, cont) { return cont() };
22103
22104 var newline = options.beautify ? function() {
22105 print("\n");
22106 } : maybe_newline;
22107
22108 var semicolon = options.beautify ? function() {
22109 print(";");
22110 } : function() {
22111 might_need_semicolon = true;
22112 };
22113
22114 function force_semicolon() {
22115 might_need_semicolon = false;
22116 print(";");
22117 };
22118
22119 function next_indent() {
22120 return indentation + options.indent_level;
22121 };
22122
22123 function with_block(cont) {
22124 var ret;
22125 print("{");
22126 newline();
22127 with_indent(next_indent(), function(){
22128 ret = cont();
22129 });
22130 indent();
22131 print("}");
22132 return ret;
22133 };
22134
22135 function with_parens(cont) {
22136 print("(");
22137 //XXX: still nice to have that for argument lists
22138 //var ret = with_indent(current_col, cont);
22139 var ret = cont();
22140 print(")");
22141 return ret;
22142 };
22143
22144 function with_square(cont) {
22145 print("[");
22146 //var ret = with_indent(current_col, cont);
22147 var ret = cont();
22148 print("]");
22149 return ret;
22150 };
22151
22152 function comma() {
22153 print(",");
22154 space();
22155 };
22156
22157 function colon() {
22158 print(":");
22159 if (options.space_colon) space();
22160 };
22161
22162 var add_mapping = options.source_map ? function(token, name) {
22163 try {
22164 if (token) options.source_map.add(
22165 token.file || "?",
22166 current_line, current_col,
22167 token.line, token.col,
22168 (!name && token.type == "name") ? token.value : name
22169 );
22170 } catch(ex) {
22171 AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
22172 file: token.file,
22173 line: token.line,
22174 col: token.col,
22175 cline: current_line,
22176 ccol: current_col,
22177 name: name || ""
22178 })
22179 }
22180 } : noop;
22181
22182 function get() {
22183 return OUTPUT;
22184 };
22185
22186 if (options.preamble) {
22187 print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
22188 }
22189
22190 var stack = [];
22191 return {
22192 get : get,
22193 toString : get,
22194 indent : indent,
22195 indentation : function() { return indentation },
22196 current_width : function() { return current_col - indentation },
22197 should_break : function() { return options.width && this.current_width() >= options.width },
22198 newline : newline,
22199 print : print,
22200 space : space,
22201 comma : comma,
22202 colon : colon,
22203 last : function() { return last },
22204 semicolon : semicolon,
22205 force_semicolon : force_semicolon,
22206 to_ascii : to_ascii,
22207 print_name : function(name) { print(make_name(name)) },
22208 print_string : function(str, quote) { print(encode_string(str, quote)) },
22209 next_indent : next_indent,
22210 with_indent : with_indent,
22211 with_block : with_block,
22212 with_parens : with_parens,
22213 with_square : with_square,
22214 add_mapping : add_mapping,
22215 option : function(opt) { return options[opt] },
22216 line : function() { return current_line },
22217 col : function() { return current_col },
22218 pos : function() { return current_pos },
22219 push_node : function(node) { stack.push(node) },
22220 pop_node : function() { return stack.pop() },
22221 stack : function() { return stack },
22222 parent : function(n) {
22223 return stack[stack.length - 2 - (n || 0)];
22224 }
22225 };
22226
22227};
22228
22229/* -----[ code generators ]----- */
22230
22231(function(){
22232
22233 /* -----[ utils ]----- */
22234
22235 function DEFPRINT(nodetype, generator) {
22236 nodetype.DEFMETHOD("_codegen", generator);
22237 };
22238
22239 var use_asm = false;
22240
22241 AST_Node.DEFMETHOD("print", function(stream, force_parens){
22242 var self = this, generator = self._codegen, prev_use_asm = use_asm;
22243 if (self instanceof AST_Directive && self.value == "use asm") {
22244 use_asm = true;
22245 }
22246 function doit() {
22247 self.add_comments(stream);
22248 self.add_source_map(stream);
22249 generator(self, stream);
22250 }
22251 stream.push_node(self);
22252 if (force_parens || self.needs_parens(stream)) {
22253 stream.with_parens(doit);
22254 } else {
22255 doit();
22256 }
22257 stream.pop_node();
22258 if (self instanceof AST_Lambda) {
22259 use_asm = prev_use_asm;
22260 }
22261 });
22262
22263 AST_Node.DEFMETHOD("print_to_string", function(options){
22264 var s = OutputStream(options);
22265 this.print(s);
22266 return s.get();
22267 });
22268
22269 /* -----[ comments ]----- */
22270
22271 AST_Node.DEFMETHOD("add_comments", function(output){
22272 var c = output.option("comments"), self = this;
22273 var start = self.start;
22274 if (start && !start._comments_dumped) {
22275 start._comments_dumped = true;
22276 var comments = start.comments_before || [];
22277
22278 // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
22279 // and https://github.com/mishoo/UglifyJS2/issues/372
22280 if (self instanceof AST_Exit && self.value) {
22281 self.value.walk(new TreeWalker(function(node){
22282 if (node.start && node.start.comments_before) {
22283 comments = comments.concat(node.start.comments_before);
22284 node.start.comments_before = [];
22285 }
22286 if (node instanceof AST_Function ||
22287 node instanceof AST_Array ||
22288 node instanceof AST_Object)
22289 {
22290 return true; // don't go inside.
22291 }
22292 }));
22293 }
22294
22295 if (!c) {
22296 comments = comments.filter(function(comment) {
22297 return comment.type == "comment5";
22298 });
22299 } else if (c.test) {
22300 comments = comments.filter(function(comment){
22301 return c.test(comment.value) || comment.type == "comment5";
22302 });
22303 } else if (typeof c == "function") {
22304 comments = comments.filter(function(comment){
22305 return c(self, comment) || comment.type == "comment5";
22306 });
22307 }
22308
22309 // Keep single line comments after nlb, after nlb
22310 if (!output.option("beautify") && comments.length > 0 &&
22311 /comment[134]/.test(comments[0].type) &&
22312 output.col() !== 0 && comments[0].nlb)
22313 {
22314 output.print("\n");
22315 }
22316
22317 comments.forEach(function(c){
22318 if (/comment[134]/.test(c.type)) {
22319 output.print("//" + c.value + "\n");
22320 output.indent();
22321 }
22322 else if (c.type == "comment2") {
22323 output.print("/*" + c.value + "*/");
22324 if (start.nlb) {
22325 output.print("\n");
22326 output.indent();
22327 } else {
22328 output.space();
22329 }
22330 }
22331 else if (output.pos() === 0 && c.type == "comment5" && output.option("shebang")) {
22332 output.print("#!" + c.value + "\n");
22333 output.indent();
22334 }
22335 });
22336 }
22337 });
22338
22339 /* -----[ PARENTHESES ]----- */
22340
22341 function PARENS(nodetype, func) {
22342 if (Array.isArray(nodetype)) {
22343 nodetype.forEach(function(nodetype){
22344 PARENS(nodetype, func);
22345 });
22346 } else {
22347 nodetype.DEFMETHOD("needs_parens", func);
22348 }
22349 };
22350
22351 PARENS(AST_Node, function(){
22352 return false;
22353 });
22354
22355 // a function expression needs parens around it when it's provably
22356 // the first token to appear in a statement.
22357 PARENS(AST_Function, function(output){
22358 return first_in_statement(output);
22359 });
22360
22361 // same goes for an object literal, because otherwise it would be
22362 // interpreted as a block of code.
22363 PARENS(AST_Object, function(output){
22364 return first_in_statement(output);
22365 });
22366
22367 PARENS([ AST_Unary, AST_Undefined ], function(output){
22368 var p = output.parent();
22369 return p instanceof AST_PropAccess && p.expression === this;
22370 });
22371
22372 PARENS(AST_Seq, function(output){
22373 var p = output.parent();
22374 return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
22375 || p instanceof AST_Unary // !(foo, bar, baz)
22376 || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
22377 || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
22378 || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
22379 || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
22380 || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
22381 || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
22382 * ==> 20 (side effect, set a := 10 and b := 20) */
22383 ;
22384 });
22385
22386 PARENS(AST_Binary, function(output){
22387 var p = output.parent();
22388 // (foo && bar)()
22389 if (p instanceof AST_Call && p.expression === this)
22390 return true;
22391 // typeof (foo && bar)
22392 if (p instanceof AST_Unary)
22393 return true;
22394 // (foo && bar)["prop"], (foo && bar).prop
22395 if (p instanceof AST_PropAccess && p.expression === this)
22396 return true;
22397 // this deals with precedence: 3 * (2 + 1)
22398 if (p instanceof AST_Binary) {
22399 var po = p.operator, pp = PRECEDENCE[po];
22400 var so = this.operator, sp = PRECEDENCE[so];
22401 if (pp > sp
22402 || (pp == sp
22403 && this === p.right)) {
22404 return true;
22405 }
22406 }
22407 });
22408
22409 PARENS(AST_PropAccess, function(output){
22410 var p = output.parent();
22411 if (p instanceof AST_New && p.expression === this) {
22412 // i.e. new (foo.bar().baz)
22413 //
22414 // if there's one call into this subtree, then we need
22415 // parens around it too, otherwise the call will be
22416 // interpreted as passing the arguments to the upper New
22417 // expression.
22418 try {
22419 this.walk(new TreeWalker(function(node){
22420 if (node instanceof AST_Call) throw p;
22421 }));
22422 } catch(ex) {
22423 if (ex !== p) throw ex;
22424 return true;
22425 }
22426 }
22427 });
22428
22429 PARENS(AST_Call, function(output){
22430 var p = output.parent(), p1;
22431 if (p instanceof AST_New && p.expression === this)
22432 return true;
22433
22434 // workaround for Safari bug.
22435 // https://bugs.webkit.org/show_bug.cgi?id=123506
22436 return this.expression instanceof AST_Function
22437 && p instanceof AST_PropAccess
22438 && p.expression === this
22439 && (p1 = output.parent(1)) instanceof AST_Assign
22440 && p1.left === p;
22441 });
22442
22443 PARENS(AST_New, function(output){
22444 var p = output.parent();
22445 if (no_constructor_parens(this, output)
22446 && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
22447 || p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
22448 return true;
22449 });
22450
22451 PARENS(AST_Number, function(output){
22452 var p = output.parent();
22453 if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
22454 return true;
22455 });
22456
22457 PARENS([ AST_Assign, AST_Conditional ], function (output){
22458 var p = output.parent();
22459 // !(a = false) → true
22460 if (p instanceof AST_Unary)
22461 return true;
22462 // 1 + (a = 2) + 3 → 6, side effect setting a = 2
22463 if (p instanceof AST_Binary && !(p instanceof AST_Assign))
22464 return true;
22465 // (a = func)() —or— new (a = Object)()
22466 if (p instanceof AST_Call && p.expression === this)
22467 return true;
22468 // (a = foo) ? bar : baz
22469 if (p instanceof AST_Conditional && p.condition === this)
22470 return true;
22471 // (a = foo)["prop"] —or— (a = foo).prop
22472 if (p instanceof AST_PropAccess && p.expression === this)
22473 return true;
22474 });
22475
22476 /* -----[ PRINTERS ]----- */
22477
22478 DEFPRINT(AST_Directive, function(self, output){
22479 output.print_string(self.value, self.quote);
22480 output.semicolon();
22481 });
22482 DEFPRINT(AST_Debugger, function(self, output){
22483 output.print("debugger");
22484 output.semicolon();
22485 });
22486
22487 /* -----[ statements ]----- */
22488
22489 function display_body(body, is_toplevel, output) {
22490 var last = body.length - 1;
22491 body.forEach(function(stmt, i){
22492 if (!(stmt instanceof AST_EmptyStatement)) {
22493 output.indent();
22494 stmt.print(output);
22495 if (!(i == last && is_toplevel)) {
22496 output.newline();
22497 if (is_toplevel) output.newline();
22498 }
22499 }
22500 });
22501 };
22502
22503 AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
22504 force_statement(this.body, output);
22505 });
22506
22507 DEFPRINT(AST_Statement, function(self, output){
22508 self.body.print(output);
22509 output.semicolon();
22510 });
22511 DEFPRINT(AST_Toplevel, function(self, output){
22512 display_body(self.body, true, output);
22513 output.print("");
22514 });
22515 DEFPRINT(AST_LabeledStatement, function(self, output){
22516 self.label.print(output);
22517 output.colon();
22518 self.body.print(output);
22519 });
22520 DEFPRINT(AST_SimpleStatement, function(self, output){
22521 self.body.print(output);
22522 output.semicolon();
22523 });
22524 function print_bracketed(body, output) {
22525 if (body.length > 0) output.with_block(function(){
22526 display_body(body, false, output);
22527 });
22528 else output.print("{}");
22529 };
22530 DEFPRINT(AST_BlockStatement, function(self, output){
22531 print_bracketed(self.body, output);
22532 });
22533 DEFPRINT(AST_EmptyStatement, function(self, output){
22534 output.semicolon();
22535 });
22536 DEFPRINT(AST_Do, function(self, output){
22537 output.print("do");
22538 output.space();
22539 self._do_print_body(output);
22540 output.space();
22541 output.print("while");
22542 output.space();
22543 output.with_parens(function(){
22544 self.condition.print(output);
22545 });
22546 output.semicolon();
22547 });
22548 DEFPRINT(AST_While, function(self, output){
22549 output.print("while");
22550 output.space();
22551 output.with_parens(function(){
22552 self.condition.print(output);
22553 });
22554 output.space();
22555 self._do_print_body(output);
22556 });
22557 DEFPRINT(AST_For, function(self, output){
22558 output.print("for");
22559 output.space();
22560 output.with_parens(function(){
22561 if (self.init && !(self.init instanceof AST_EmptyStatement)) {
22562 if (self.init instanceof AST_Definitions) {
22563 self.init.print(output);
22564 } else {
22565 parenthesize_for_noin(self.init, output, true);
22566 }
22567 output.print(";");
22568 output.space();
22569 } else {
22570 output.print(";");
22571 }
22572 if (self.condition) {
22573 self.condition.print(output);
22574 output.print(";");
22575 output.space();
22576 } else {
22577 output.print(";");
22578 }
22579 if (self.step) {
22580 self.step.print(output);
22581 }
22582 });
22583 output.space();
22584 self._do_print_body(output);
22585 });
22586 DEFPRINT(AST_ForIn, function(self, output){
22587 output.print("for");
22588 output.space();
22589 output.with_parens(function(){
22590 self.init.print(output);
22591 output.space();
22592 output.print("in");
22593 output.space();
22594 self.object.print(output);
22595 });
22596 output.space();
22597 self._do_print_body(output);
22598 });
22599 DEFPRINT(AST_With, function(self, output){
22600 output.print("with");
22601 output.space();
22602 output.with_parens(function(){
22603 self.expression.print(output);
22604 });
22605 output.space();
22606 self._do_print_body(output);
22607 });
22608
22609 /* -----[ functions ]----- */
22610 AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
22611 var self = this;
22612 if (!nokeyword) {
22613 output.print("function");
22614 }
22615 if (self.name) {
22616 output.space();
22617 self.name.print(output);
22618 }
22619 output.with_parens(function(){
22620 self.argnames.forEach(function(arg, i){
22621 if (i) output.comma();
22622 arg.print(output);
22623 });
22624 });
22625 output.space();
22626 print_bracketed(self.body, output);
22627 });
22628 DEFPRINT(AST_Lambda, function(self, output){
22629 self._do_print(output);
22630 });
22631
22632 /* -----[ exits ]----- */
22633 AST_Exit.DEFMETHOD("_do_print", function(output, kind){
22634 output.print(kind);
22635 if (this.value) {
22636 output.space();
22637 this.value.print(output);
22638 }
22639 output.semicolon();
22640 });
22641 DEFPRINT(AST_Return, function(self, output){
22642 self._do_print(output, "return");
22643 });
22644 DEFPRINT(AST_Throw, function(self, output){
22645 self._do_print(output, "throw");
22646 });
22647
22648 /* -----[ loop control ]----- */
22649 AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
22650 output.print(kind);
22651 if (this.label) {
22652 output.space();
22653 this.label.print(output);
22654 }
22655 output.semicolon();
22656 });
22657 DEFPRINT(AST_Break, function(self, output){
22658 self._do_print(output, "break");
22659 });
22660 DEFPRINT(AST_Continue, function(self, output){
22661 self._do_print(output, "continue");
22662 });
22663
22664 /* -----[ if ]----- */
22665 function make_then(self, output) {
22666 if (output.option("bracketize")) {
22667 make_block(self.body, output);
22668 return;
22669 }
22670 // The squeezer replaces "block"-s that contain only a single
22671 // statement with the statement itself; technically, the AST
22672 // is correct, but this can create problems when we output an
22673 // IF having an ELSE clause where the THEN clause ends in an
22674 // IF *without* an ELSE block (then the outer ELSE would refer
22675 // to the inner IF). This function checks for this case and
22676 // adds the block brackets if needed.
22677 if (!self.body)
22678 return output.force_semicolon();
22679 if (self.body instanceof AST_Do
22680 && !output.option("screw_ie8")) {
22681 // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
22682 // croaks with "syntax error" on code like this: if (foo)
22683 // do ... while(cond); else ... we need block brackets
22684 // around do/while
22685 make_block(self.body, output);
22686 return;
22687 }
22688 var b = self.body;
22689 while (true) {
22690 if (b instanceof AST_If) {
22691 if (!b.alternative) {
22692 make_block(self.body, output);
22693 return;
22694 }
22695 b = b.alternative;
22696 }
22697 else if (b instanceof AST_StatementWithBody) {
22698 b = b.body;
22699 }
22700 else break;
22701 }
22702 force_statement(self.body, output);
22703 };
22704 DEFPRINT(AST_If, function(self, output){
22705 output.print("if");
22706 output.space();
22707 output.with_parens(function(){
22708 self.condition.print(output);
22709 });
22710 output.space();
22711 if (self.alternative) {
22712 make_then(self, output);
22713 output.space();
22714 output.print("else");
22715 output.space();
22716 force_statement(self.alternative, output);
22717 } else {
22718 self._do_print_body(output);
22719 }
22720 });
22721
22722 /* -----[ switch ]----- */
22723 DEFPRINT(AST_Switch, function(self, output){
22724 output.print("switch");
22725 output.space();
22726 output.with_parens(function(){
22727 self.expression.print(output);
22728 });
22729 output.space();
22730 if (self.body.length > 0) output.with_block(function(){
22731 self.body.forEach(function(stmt, i){
22732 if (i) output.newline();
22733 output.indent(true);
22734 stmt.print(output);
22735 });
22736 });
22737 else output.print("{}");
22738 });
22739 AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
22740 if (this.body.length > 0) {
22741 output.newline();
22742 this.body.forEach(function(stmt){
22743 output.indent();
22744 stmt.print(output);
22745 output.newline();
22746 });
22747 }
22748 });
22749 DEFPRINT(AST_Default, function(self, output){
22750 output.print("default:");
22751 self._do_print_body(output);
22752 });
22753 DEFPRINT(AST_Case, function(self, output){
22754 output.print("case");
22755 output.space();
22756 self.expression.print(output);
22757 output.print(":");
22758 self._do_print_body(output);
22759 });
22760
22761 /* -----[ exceptions ]----- */
22762 DEFPRINT(AST_Try, function(self, output){
22763 output.print("try");
22764 output.space();
22765 print_bracketed(self.body, output);
22766 if (self.bcatch) {
22767 output.space();
22768 self.bcatch.print(output);
22769 }
22770 if (self.bfinally) {
22771 output.space();
22772 self.bfinally.print(output);
22773 }
22774 });
22775 DEFPRINT(AST_Catch, function(self, output){
22776 output.print("catch");
22777 output.space();
22778 output.with_parens(function(){
22779 self.argname.print(output);
22780 });
22781 output.space();
22782 print_bracketed(self.body, output);
22783 });
22784 DEFPRINT(AST_Finally, function(self, output){
22785 output.print("finally");
22786 output.space();
22787 print_bracketed(self.body, output);
22788 });
22789
22790 /* -----[ var/const ]----- */
22791 AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
22792 output.print(kind);
22793 output.space();
22794 this.definitions.forEach(function(def, i){
22795 if (i) output.comma();
22796 def.print(output);
22797 });
22798 var p = output.parent();
22799 var in_for = p instanceof AST_For || p instanceof AST_ForIn;
22800 var avoid_semicolon = in_for && p.init === this;
22801 if (!avoid_semicolon)
22802 output.semicolon();
22803 });
22804 DEFPRINT(AST_Var, function(self, output){
22805 self._do_print(output, "var");
22806 });
22807 DEFPRINT(AST_Const, function(self, output){
22808 self._do_print(output, "const");
22809 });
22810
22811 function parenthesize_for_noin(node, output, noin) {
22812 if (!noin) node.print(output);
22813 else try {
22814 // need to take some precautions here:
22815 // https://github.com/mishoo/UglifyJS2/issues/60
22816 node.walk(new TreeWalker(function(node){
22817 if (node instanceof AST_Binary && node.operator == "in")
22818 throw output;
22819 }));
22820 node.print(output);
22821 } catch(ex) {
22822 if (ex !== output) throw ex;
22823 node.print(output, true);
22824 }
22825 };
22826
22827 DEFPRINT(AST_VarDef, function(self, output){
22828 self.name.print(output);
22829 if (self.value) {
22830 output.space();
22831 output.print("=");
22832 output.space();
22833 var p = output.parent(1);
22834 var noin = p instanceof AST_For || p instanceof AST_ForIn;
22835 parenthesize_for_noin(self.value, output, noin);
22836 }
22837 });
22838
22839 /* -----[ other expressions ]----- */
22840 DEFPRINT(AST_Call, function(self, output){
22841 self.expression.print(output);
22842 if (self instanceof AST_New && no_constructor_parens(self, output))
22843 return;
22844 output.with_parens(function(){
22845 self.args.forEach(function(expr, i){
22846 if (i) output.comma();
22847 expr.print(output);
22848 });
22849 });
22850 });
22851 DEFPRINT(AST_New, function(self, output){
22852 output.print("new");
22853 output.space();
22854 AST_Call.prototype._codegen(self, output);
22855 });
22856
22857 AST_Seq.DEFMETHOD("_do_print", function(output){
22858 this.car.print(output);
22859 if (this.cdr) {
22860 output.comma();
22861 if (output.should_break()) {
22862 output.newline();
22863 output.indent();
22864 }
22865 this.cdr.print(output);
22866 }
22867 });
22868 DEFPRINT(AST_Seq, function(self, output){
22869 self._do_print(output);
22870 // var p = output.parent();
22871 // if (p instanceof AST_Statement) {
22872 // output.with_indent(output.next_indent(), function(){
22873 // self._do_print(output);
22874 // });
22875 // } else {
22876 // self._do_print(output);
22877 // }
22878 });
22879 DEFPRINT(AST_Dot, function(self, output){
22880 var expr = self.expression;
22881 expr.print(output);
22882 if (expr instanceof AST_Number && expr.getValue() >= 0) {
22883 if (!/[xa-f.]/i.test(output.last())) {
22884 output.print(".");
22885 }
22886 }
22887 output.print(".");
22888 // the name after dot would be mapped about here.
22889 output.add_mapping(self.end);
22890 output.print_name(self.property);
22891 });
22892 DEFPRINT(AST_Sub, function(self, output){
22893 self.expression.print(output);
22894 output.print("[");
22895 self.property.print(output);
22896 output.print("]");
22897 });
22898 DEFPRINT(AST_UnaryPrefix, function(self, output){
22899 var op = self.operator;
22900 output.print(op);
22901 if (/^[a-z]/i.test(op)
22902 || (/[+-]$/.test(op)
22903 && self.expression instanceof AST_UnaryPrefix
22904 && /^[+-]/.test(self.expression.operator))) {
22905 output.space();
22906 }
22907 self.expression.print(output);
22908 });
22909 DEFPRINT(AST_UnaryPostfix, function(self, output){
22910 self.expression.print(output);
22911 output.print(self.operator);
22912 });
22913 DEFPRINT(AST_Binary, function(self, output){
22914 var op = self.operator;
22915 self.left.print(output);
22916 if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
22917 && self.left instanceof AST_UnaryPostfix
22918 && self.left.operator == "--") {
22919 // space is mandatory to avoid outputting -->
22920 output.print(" ");
22921 } else {
22922 // the space is optional depending on "beautify"
22923 output.space();
22924 }
22925 output.print(op);
22926 if ((op == "<" || op == "<<")
22927 && self.right instanceof AST_UnaryPrefix
22928 && self.right.operator == "!"
22929 && self.right.expression instanceof AST_UnaryPrefix
22930 && self.right.expression.operator == "--") {
22931 // space is mandatory to avoid outputting <!--
22932 output.print(" ");
22933 } else {
22934 // the space is optional depending on "beautify"
22935 output.space();
22936 }
22937 self.right.print(output);
22938 });
22939 DEFPRINT(AST_Conditional, function(self, output){
22940 self.condition.print(output);
22941 output.space();
22942 output.print("?");
22943 output.space();
22944 self.consequent.print(output);
22945 output.space();
22946 output.colon();
22947 self.alternative.print(output);
22948 });
22949
22950 /* -----[ literals ]----- */
22951 DEFPRINT(AST_Array, function(self, output){
22952 output.with_square(function(){
22953 var a = self.elements, len = a.length;
22954 if (len > 0) output.space();
22955 a.forEach(function(exp, i){
22956 if (i) output.comma();
22957 exp.print(output);
22958 // If the final element is a hole, we need to make sure it
22959 // doesn't look like a trailing comma, by inserting an actual
22960 // trailing comma.
22961 if (i === len - 1 && exp instanceof AST_Hole)
22962 output.comma();
22963 });
22964 if (len > 0) output.space();
22965 });
22966 });
22967 DEFPRINT(AST_Object, function(self, output){
22968 if (self.properties.length > 0) output.with_block(function(){
22969 self.properties.forEach(function(prop, i){
22970 if (i) {
22971 output.print(",");
22972 output.newline();
22973 }
22974 output.indent();
22975 prop.print(output);
22976 });
22977 output.newline();
22978 });
22979 else output.print("{}");
22980 });
22981 DEFPRINT(AST_ObjectKeyVal, function(self, output){
22982 var key = self.key;
22983 var quote = self.quote;
22984 if (output.option("quote_keys")) {
22985 output.print_string(key + "");
22986 } else if ((typeof key == "number"
22987 || !output.option("beautify")
22988 && +key + "" == key)
22989 && parseFloat(key) >= 0) {
22990 output.print(make_num(key));
22991 } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
22992 output.print_name(key);
22993 } else {
22994 output.print_string(key, quote);
22995 }
22996 output.colon();
22997 self.value.print(output);
22998 });
22999 DEFPRINT(AST_ObjectSetter, function(self, output){
23000 output.print("set");
23001 output.space();
23002 self.key.print(output);
23003 self.value._do_print(output, true);
23004 });
23005 DEFPRINT(AST_ObjectGetter, function(self, output){
23006 output.print("get");
23007 output.space();
23008 self.key.print(output);
23009 self.value._do_print(output, true);
23010 });
23011 DEFPRINT(AST_Symbol, function(self, output){
23012 var def = self.definition();
23013 output.print_name(def ? def.mangled_name || def.name : self.name);
23014 });
23015 DEFPRINT(AST_Undefined, function(self, output){
23016 output.print("void 0");
23017 });
23018 DEFPRINT(AST_Hole, noop);
23019 DEFPRINT(AST_Infinity, function(self, output){
23020 output.print("Infinity");
23021 });
23022 DEFPRINT(AST_NaN, function(self, output){
23023 output.print("NaN");
23024 });
23025 DEFPRINT(AST_This, function(self, output){
23026 output.print("this");
23027 });
23028 DEFPRINT(AST_Constant, function(self, output){
23029 output.print(self.getValue());
23030 });
23031 DEFPRINT(AST_String, function(self, output){
23032 output.print_string(self.getValue(), self.quote);
23033 });
23034 DEFPRINT(AST_Number, function(self, output){
23035 if (use_asm && self.start.raw != null) {
23036 output.print(self.start.raw);
23037 } else {
23038 output.print(make_num(self.getValue()));
23039 }
23040 });
23041
23042 function regexp_safe_literal(code) {
23043 return [
23044 0x5c , // \
23045 0x2f , // /
23046 0x2e , // .
23047 0x2b , // +
23048 0x2a , // *
23049 0x3f , // ?
23050 0x28 , // (
23051 0x29 , // )
23052 0x5b , // [
23053 0x5d , // ]
23054 0x7b , // {
23055 0x7d , // }
23056 0x24 , // $
23057 0x5e , // ^
23058 0x3a , // :
23059 0x7c , // |
23060 0x21 , // !
23061 0x0a , // \n
23062 0x0d , // \r
23063 0x00 , // \0
23064 0xfeff , // Unicode BOM
23065 0x2028 , // unicode "line separator"
23066 0x2029 , // unicode "paragraph separator"
23067 ].indexOf(code) < 0;
23068 };
23069
23070 DEFPRINT(AST_RegExp, function(self, output){
23071 var str = self.getValue().toString();
23072 if (output.option("ascii_only")) {
23073 str = output.to_ascii(str);
23074 } else if (output.option("unescape_regexps")) {
23075 str = str.split("\\\\").map(function(str){
23076 return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
23077 var code = parseInt(s.substr(2), 16);
23078 return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
23079 });
23080 }).join("\\\\");
23081 }
23082 output.print(str);
23083 var p = output.parent();
23084 if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
23085 output.print(" ");
23086 });
23087
23088 function force_statement(stat, output) {
23089 if (output.option("bracketize")) {
23090 if (!stat || stat instanceof AST_EmptyStatement)
23091 output.print("{}");
23092 else if (stat instanceof AST_BlockStatement)
23093 stat.print(output);
23094 else output.with_block(function(){
23095 output.indent();
23096 stat.print(output);
23097 output.newline();
23098 });
23099 } else {
23100 if (!stat || stat instanceof AST_EmptyStatement)
23101 output.force_semicolon();
23102 else
23103 stat.print(output);
23104 }
23105 };
23106
23107 // return true if the node at the top of the stack (that means the
23108 // innermost node in the current output) is lexically the first in
23109 // a statement.
23110 function first_in_statement(output) {
23111 var a = output.stack(), i = a.length, node = a[--i], p = a[--i];
23112 while (i > 0) {
23113 if (p instanceof AST_Statement && p.body === node)
23114 return true;
23115 if ((p instanceof AST_Seq && p.car === node ) ||
23116 (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
23117 (p instanceof AST_Dot && p.expression === node ) ||
23118 (p instanceof AST_Sub && p.expression === node ) ||
23119 (p instanceof AST_Conditional && p.condition === node ) ||
23120 (p instanceof AST_Binary && p.left === node ) ||
23121 (p instanceof AST_UnaryPostfix && p.expression === node ))
23122 {
23123 node = p;
23124 p = a[--i];
23125 } else {
23126 return false;
23127 }
23128 }
23129 };
23130
23131 // self should be AST_New. decide if we want to show parens or not.
23132 function no_constructor_parens(self, output) {
23133 return self.args.length == 0 && !output.option("beautify");
23134 };
23135
23136 function best_of(a) {
23137 var best = a[0], len = best.length;
23138 for (var i = 1; i < a.length; ++i) {
23139 if (a[i].length < len) {
23140 best = a[i];
23141 len = best.length;
23142 }
23143 }
23144 return best;
23145 };
23146
23147 function make_num(num) {
23148 var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
23149 if (Math.floor(num) === num) {
23150 if (num >= 0) {
23151 a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
23152 "0" + num.toString(8)); // same.
23153 } else {
23154 a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
23155 "-0" + (-num).toString(8)); // same.
23156 }
23157 if ((m = /^(.*?)(0+)$/.exec(num))) {
23158 a.push(m[1] + "e" + m[2].length);
23159 }
23160 } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
23161 a.push(m[2] + "e-" + (m[1].length + m[2].length),
23162 str.substr(str.indexOf(".")));
23163 }
23164 return best_of(a);
23165 };
23166
23167 function make_block(stmt, output) {
23168 if (stmt instanceof AST_BlockStatement) {
23169 stmt.print(output);
23170 return;
23171 }
23172 output.with_block(function(){
23173 output.indent();
23174 stmt.print(output);
23175 output.newline();
23176 });
23177 };
23178
23179 /* -----[ source map generators ]----- */
23180
23181 function DEFMAP(nodetype, generator) {
23182 nodetype.DEFMETHOD("add_source_map", function(stream){
23183 generator(this, stream);
23184 });
23185 };
23186
23187 // We could easily add info for ALL nodes, but it seems to me that
23188 // would be quite wasteful, hence this noop in the base class.
23189 DEFMAP(AST_Node, noop);
23190
23191 function basic_sourcemap_gen(self, output) {
23192 output.add_mapping(self.start);
23193 };
23194
23195 // XXX: I'm not exactly sure if we need it for all of these nodes,
23196 // or if we should add even more.
23197
23198 DEFMAP(AST_Directive, basic_sourcemap_gen);
23199 DEFMAP(AST_Debugger, basic_sourcemap_gen);
23200 DEFMAP(AST_Symbol, basic_sourcemap_gen);
23201 DEFMAP(AST_Jump, basic_sourcemap_gen);
23202 DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
23203 DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it
23204 DEFMAP(AST_Lambda, basic_sourcemap_gen);
23205 DEFMAP(AST_Switch, basic_sourcemap_gen);
23206 DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
23207 DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
23208 DEFMAP(AST_Toplevel, noop);
23209 DEFMAP(AST_New, basic_sourcemap_gen);
23210 DEFMAP(AST_Try, basic_sourcemap_gen);
23211 DEFMAP(AST_Catch, basic_sourcemap_gen);
23212 DEFMAP(AST_Finally, basic_sourcemap_gen);
23213 DEFMAP(AST_Definitions, basic_sourcemap_gen);
23214 DEFMAP(AST_Constant, basic_sourcemap_gen);
23215 DEFMAP(AST_ObjectSetter, function(self, output){
23216 output.add_mapping(self.start, self.key.name);
23217 });
23218 DEFMAP(AST_ObjectGetter, function(self, output){
23219 output.add_mapping(self.start, self.key.name);
23220 });
23221 DEFMAP(AST_ObjectProperty, function(self, output){
23222 output.add_mapping(self.start, self.key);
23223 });
23224
23225})();
23226
23227/***********************************************************************
23228
23229 A JavaScript tokenizer / parser / beautifier / compressor.
23230 https://github.com/mishoo/UglifyJS2
23231
23232 -------------------------------- (C) ---------------------------------
23233
23234 Author: Mihai Bazon
23235 <mihai.bazon@gmail.com>
23236 http://mihai.bazon.net/blog
23237
23238 Distributed under the BSD license:
23239
23240 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
23241
23242 Redistribution and use in source and binary forms, with or without
23243 modification, are permitted provided that the following conditions
23244 are met:
23245
23246 * Redistributions of source code must retain the above
23247 copyright notice, this list of conditions and the following
23248 disclaimer.
23249
23250 * Redistributions in binary form must reproduce the above
23251 copyright notice, this list of conditions and the following
23252 disclaimer in the documentation and/or other materials
23253 provided with the distribution.
23254
23255 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
23256 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23257 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23258 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
23259 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23260 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23261 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23262 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23263 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23264 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
23265 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23266 SUCH DAMAGE.
23267
23268 ***********************************************************************/
23269
23270"use strict";
23271
23272function Compressor(options, false_by_default) {
23273 if (!(this instanceof Compressor))
23274 return new Compressor(options, false_by_default);
23275 TreeTransformer.call(this, this.before, this.after);
23276 this.options = defaults(options, {
23277 sequences : !false_by_default,
23278 properties : !false_by_default,
23279 dead_code : !false_by_default,
23280 drop_debugger : !false_by_default,
23281 unsafe : false,
23282 unsafe_comps : false,
23283 conditionals : !false_by_default,
23284 comparisons : !false_by_default,
23285 evaluate : !false_by_default,
23286 booleans : !false_by_default,
23287 loops : !false_by_default,
23288 unused : !false_by_default,
23289 hoist_funs : !false_by_default,
23290 keep_fargs : true,
23291 keep_fnames : false,
23292 hoist_vars : false,
23293 if_return : !false_by_default,
23294 join_vars : !false_by_default,
23295 cascade : !false_by_default,
23296 side_effects : !false_by_default,
23297 pure_getters : false,
23298 pure_funcs : null,
23299 negate_iife : !false_by_default,
23300 screw_ie8 : false,
23301 drop_console : false,
23302 angular : false,
23303
23304 warnings : true,
23305 global_defs : {}
23306 }, true);
23307};
23308
23309Compressor.prototype = new TreeTransformer;
23310merge(Compressor.prototype, {
23311 option: function(key) { return this.options[key] },
23312 warn: function() {
23313 if (this.options.warnings)
23314 AST_Node.warn.apply(AST_Node, arguments);
23315 },
23316 before: function(node, descend, in_list) {
23317 if (node._squeezed) return node;
23318 var was_scope = false;
23319 if (node instanceof AST_Scope) {
23320 node = node.hoist_declarations(this);
23321 was_scope = true;
23322 }
23323 descend(node, this);
23324 node = node.optimize(this);
23325 if (was_scope && node instanceof AST_Scope) {
23326 node.drop_unused(this);
23327 descend(node, this);
23328 }
23329 node._squeezed = true;
23330 return node;
23331 }
23332});
23333
23334(function(){
23335
23336 function OPT(node, optimizer) {
23337 node.DEFMETHOD("optimize", function(compressor){
23338 var self = this;
23339 if (self._optimized) return self;
23340 if (compressor.has_directive("use asm")) return self;
23341 var opt = optimizer(self, compressor);
23342 opt._optimized = true;
23343 if (opt === self) return opt;
23344 return opt.transform(compressor);
23345 });
23346 };
23347
23348 OPT(AST_Node, function(self, compressor){
23349 return self;
23350 });
23351
23352 AST_Node.DEFMETHOD("equivalent_to", function(node){
23353 // XXX: this is a rather expensive way to test two node's equivalence:
23354 return this.print_to_string() == node.print_to_string();
23355 });
23356
23357 function make_node(ctor, orig, props) {
23358 if (!props) props = {};
23359 if (orig) {
23360 if (!props.start) props.start = orig.start;
23361 if (!props.end) props.end = orig.end;
23362 }
23363 return new ctor(props);
23364 };
23365
23366 function make_node_from_constant(compressor, val, orig) {
23367 // XXX: WIP.
23368 // if (val instanceof AST_Node) return val.transform(new TreeTransformer(null, function(node){
23369 // if (node instanceof AST_SymbolRef) {
23370 // var scope = compressor.find_parent(AST_Scope);
23371 // var def = scope.find_variable(node);
23372 // node.thedef = def;
23373 // return node;
23374 // }
23375 // })).transform(compressor);
23376
23377 if (val instanceof AST_Node) return val.transform(compressor);
23378 switch (typeof val) {
23379 case "string":
23380 return make_node(AST_String, orig, {
23381 value: val
23382 }).optimize(compressor);
23383 case "number":
23384 return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {
23385 value: val
23386 }).optimize(compressor);
23387 case "boolean":
23388 return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
23389 case "undefined":
23390 return make_node(AST_Undefined, orig).optimize(compressor);
23391 default:
23392 if (val === null) {
23393 return make_node(AST_Null, orig, { value: null }).optimize(compressor);
23394 }
23395 if (val instanceof RegExp) {
23396 return make_node(AST_RegExp, orig, { value: val }).optimize(compressor);
23397 }
23398 throw new Error(string_template("Can't handle constant of type: {type}", {
23399 type: typeof val
23400 }));
23401 }
23402 };
23403
23404 function as_statement_array(thing) {
23405 if (thing === null) return [];
23406 if (thing instanceof AST_BlockStatement) return thing.body;
23407 if (thing instanceof AST_EmptyStatement) return [];
23408 if (thing instanceof AST_Statement) return [ thing ];
23409 throw new Error("Can't convert thing to statement array");
23410 };
23411
23412 function is_empty(thing) {
23413 if (thing === null) return true;
23414 if (thing instanceof AST_EmptyStatement) return true;
23415 if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
23416 return false;
23417 };
23418
23419 function loop_body(x) {
23420 if (x instanceof AST_Switch) return x;
23421 if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
23422 return (x.body instanceof AST_BlockStatement ? x.body : x);
23423 }
23424 return x;
23425 };
23426
23427 function tighten_body(statements, compressor) {
23428 var CHANGED, max_iter = 10;
23429 do {
23430 CHANGED = false;
23431 if (compressor.option("angular")) {
23432 statements = process_for_angular(statements);
23433 }
23434 statements = eliminate_spurious_blocks(statements);
23435 if (compressor.option("dead_code")) {
23436 statements = eliminate_dead_code(statements, compressor);
23437 }
23438 if (compressor.option("if_return")) {
23439 statements = handle_if_return(statements, compressor);
23440 }
23441 if (compressor.option("sequences")) {
23442 statements = sequencesize(statements, compressor);
23443 }
23444 if (compressor.option("join_vars")) {
23445 statements = join_consecutive_vars(statements, compressor);
23446 }
23447 } while (CHANGED && max_iter-- > 0);
23448
23449 if (compressor.option("negate_iife")) {
23450 negate_iifes(statements, compressor);
23451 }
23452
23453 return statements;
23454
23455 function process_for_angular(statements) {
23456 function has_inject(comment) {
23457 return /@ngInject/.test(comment.value);
23458 }
23459 function make_arguments_names_list(func) {
23460 return func.argnames.map(function(sym){
23461 return make_node(AST_String, sym, { value: sym.name });
23462 });
23463 }
23464 function make_array(orig, elements) {
23465 return make_node(AST_Array, orig, { elements: elements });
23466 }
23467 function make_injector(func, name) {
23468 return make_node(AST_SimpleStatement, func, {
23469 body: make_node(AST_Assign, func, {
23470 operator: "=",
23471 left: make_node(AST_Dot, name, {
23472 expression: make_node(AST_SymbolRef, name, name),
23473 property: "$inject"
23474 }),
23475 right: make_array(func, make_arguments_names_list(func))
23476 })
23477 });
23478 }
23479 function check_expression(body) {
23480 if (body && body.args) {
23481 // if this is a function call check all of arguments passed
23482 body.args.forEach(function(argument, index, array) {
23483 var comments = argument.start.comments_before;
23484 // if the argument is function preceded by @ngInject
23485 if (argument instanceof AST_Lambda && comments.length && has_inject(comments[0])) {
23486 // replace the function with an array of names of its parameters and function at the end
23487 array[index] = make_array(argument, make_arguments_names_list(argument).concat(argument));
23488 }
23489 });
23490 // if this is chained call check previous one recursively
23491 if (body.expression && body.expression.expression) {
23492 check_expression(body.expression.expression);
23493 }
23494 }
23495 }
23496 return statements.reduce(function(a, stat){
23497 a.push(stat);
23498
23499 if (stat.body && stat.body.args) {
23500 check_expression(stat.body);
23501 } else {
23502 var token = stat.start;
23503 var comments = token.comments_before;
23504 if (comments && comments.length > 0) {
23505 var last = comments.pop();
23506 if (has_inject(last)) {
23507 // case 1: defun
23508 if (stat instanceof AST_Defun) {
23509 a.push(make_injector(stat, stat.name));
23510 }
23511 else if (stat instanceof AST_Definitions) {
23512 stat.definitions.forEach(function(def) {
23513 if (def.value && def.value instanceof AST_Lambda) {
23514 a.push(make_injector(def.value, def.name));
23515 }
23516 });
23517 }
23518 else {
23519 compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token);
23520 }
23521 }
23522 }
23523 }
23524
23525 return a;
23526 }, []);
23527 }
23528
23529 function eliminate_spurious_blocks(statements) {
23530 var seen_dirs = [];
23531 return statements.reduce(function(a, stat){
23532 if (stat instanceof AST_BlockStatement) {
23533 CHANGED = true;
23534 a.push.apply(a, eliminate_spurious_blocks(stat.body));
23535 } else if (stat instanceof AST_EmptyStatement) {
23536 CHANGED = true;
23537 } else if (stat instanceof AST_Directive) {
23538 if (seen_dirs.indexOf(stat.value) < 0) {
23539 a.push(stat);
23540 seen_dirs.push(stat.value);
23541 } else {
23542 CHANGED = true;
23543 }
23544 } else {
23545 a.push(stat);
23546 }
23547 return a;
23548 }, []);
23549 };
23550
23551 function handle_if_return(statements, compressor) {
23552 var self = compressor.self();
23553 var in_lambda = self instanceof AST_Lambda;
23554 var ret = [];
23555 loop: for (var i = statements.length; --i >= 0;) {
23556 var stat = statements[i];
23557 switch (true) {
23558 case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
23559 CHANGED = true;
23560 // note, ret.length is probably always zero
23561 // because we drop unreachable code before this
23562 // step. nevertheless, it's good to check.
23563 continue loop;
23564 case stat instanceof AST_If:
23565 if (stat.body instanceof AST_Return) {
23566 //---
23567 // pretty silly case, but:
23568 // if (foo()) return; return; ==> foo(); return;
23569 if (((in_lambda && ret.length == 0)
23570 || (ret[0] instanceof AST_Return && !ret[0].value))
23571 && !stat.body.value && !stat.alternative) {
23572 CHANGED = true;
23573 var cond = make_node(AST_SimpleStatement, stat.condition, {
23574 body: stat.condition
23575 });
23576 ret.unshift(cond);
23577 continue loop;
23578 }
23579 //---
23580 // if (foo()) return x; return y; ==> return foo() ? x : y;
23581 if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
23582 CHANGED = true;
23583 stat = stat.clone();
23584 stat.alternative = ret[0];
23585 ret[0] = stat.transform(compressor);
23586 continue loop;
23587 }
23588 //---
23589 // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
23590 if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {
23591 CHANGED = true;
23592 stat = stat.clone();
23593 stat.alternative = ret[0] || make_node(AST_Return, stat, {
23594 value: make_node(AST_Undefined, stat)
23595 });
23596 ret[0] = stat.transform(compressor);
23597 continue loop;
23598 }
23599 //---
23600 // if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }
23601 if (!stat.body.value && in_lambda) {
23602 CHANGED = true;
23603 stat = stat.clone();
23604 stat.condition = stat.condition.negate(compressor);
23605 stat.body = make_node(AST_BlockStatement, stat, {
23606 body: as_statement_array(stat.alternative).concat(ret)
23607 });
23608 stat.alternative = null;
23609 ret = [ stat.transform(compressor) ];
23610 continue loop;
23611 }
23612 //---
23613 // XXX: what was the intention of this case?
23614 // if sequences is not enabled, this can lead to an endless loop (issue #866).
23615 // however, with sequences on this helps producing slightly better output for
23616 // the example code.
23617 if (compressor.option("sequences")
23618 && ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
23619 && (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
23620 CHANGED = true;
23621 ret.push(make_node(AST_Return, ret[0], {
23622 value: make_node(AST_Undefined, ret[0])
23623 }).transform(compressor));
23624 ret = as_statement_array(stat.alternative).concat(ret);
23625 ret.unshift(stat);
23626 continue loop;
23627 }
23628 }
23629
23630 var ab = aborts(stat.body);
23631 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
23632 if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
23633 || (ab instanceof AST_Continue && self === loop_body(lct))
23634 || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
23635 if (ab.label) {
23636 remove(ab.label.thedef.references, ab);
23637 }
23638 CHANGED = true;
23639 var body = as_statement_array(stat.body).slice(0, -1);
23640 stat = stat.clone();
23641 stat.condition = stat.condition.negate(compressor);
23642 stat.body = make_node(AST_BlockStatement, stat, {
23643 body: as_statement_array(stat.alternative).concat(ret)
23644 });
23645 stat.alternative = make_node(AST_BlockStatement, stat, {
23646 body: body
23647 });
23648 ret = [ stat.transform(compressor) ];
23649 continue loop;
23650 }
23651
23652 var ab = aborts(stat.alternative);
23653 var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab.label) : null;
23654 if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
23655 || (ab instanceof AST_Continue && self === loop_body(lct))
23656 || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
23657 if (ab.label) {
23658 remove(ab.label.thedef.references, ab);
23659 }
23660 CHANGED = true;
23661 stat = stat.clone();
23662 stat.body = make_node(AST_BlockStatement, stat.body, {
23663 body: as_statement_array(stat.body).concat(ret)
23664 });
23665 stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
23666 body: as_statement_array(stat.alternative).slice(0, -1)
23667 });
23668 ret = [ stat.transform(compressor) ];
23669 continue loop;
23670 }
23671
23672 ret.unshift(stat);
23673 break;
23674 default:
23675 ret.unshift(stat);
23676 break;
23677 }
23678 }
23679 return ret;
23680 };
23681
23682 function eliminate_dead_code(statements, compressor) {
23683 var has_quit = false;
23684 var orig = statements.length;
23685 var self = compressor.self();
23686 statements = statements.reduce(function(a, stat){
23687 if (has_quit) {
23688 extract_declarations_from_unreachable_code(compressor, stat, a);
23689 } else {
23690 if (stat instanceof AST_LoopControl) {
23691 var lct = compressor.loopcontrol_target(stat.label);
23692 if ((stat instanceof AST_Break
23693 && lct instanceof AST_BlockStatement
23694 && loop_body(lct) === self) || (stat instanceof AST_Continue
23695 && loop_body(lct) === self)) {
23696 if (stat.label) {
23697 remove(stat.label.thedef.references, stat);
23698 }
23699 } else {
23700 a.push(stat);
23701 }
23702 } else {
23703 a.push(stat);
23704 }
23705 if (aborts(stat)) has_quit = true;
23706 }
23707 return a;
23708 }, []);
23709 CHANGED = statements.length != orig;
23710 return statements;
23711 };
23712
23713 function sequencesize(statements, compressor) {
23714 if (statements.length < 2) return statements;
23715 var seq = [], ret = [];
23716 function push_seq() {
23717 seq = AST_Seq.from_array(seq);
23718 if (seq) ret.push(make_node(AST_SimpleStatement, seq, {
23719 body: seq
23720 }));
23721 seq = [];
23722 };
23723 statements.forEach(function(stat){
23724 if (stat instanceof AST_SimpleStatement && seq.length < 2000) seq.push(stat.body);
23725 else push_seq(), ret.push(stat);
23726 });
23727 push_seq();
23728 ret = sequencesize_2(ret, compressor);
23729 CHANGED = ret.length != statements.length;
23730 return ret;
23731 };
23732
23733 function sequencesize_2(statements, compressor) {
23734 function cons_seq(right) {
23735 ret.pop();
23736 var left = prev.body;
23737 if (left instanceof AST_Seq) {
23738 left.add(right);
23739 } else {
23740 left = AST_Seq.cons(left, right);
23741 }
23742 return left.transform(compressor);
23743 };
23744 var ret = [], prev = null;
23745 statements.forEach(function(stat){
23746 if (prev) {
23747 if (stat instanceof AST_For) {
23748 var opera = {};
23749 try {
23750 prev.body.walk(new TreeWalker(function(node){
23751 if (node instanceof AST_Binary && node.operator == "in")
23752 throw opera;
23753 }));
23754 if (stat.init && !(stat.init instanceof AST_Definitions)) {
23755 stat.init = cons_seq(stat.init);
23756 }
23757 else if (!stat.init) {
23758 stat.init = prev.body;
23759 ret.pop();
23760 }
23761 } catch(ex) {
23762 if (ex !== opera) throw ex;
23763 }
23764 }
23765 else if (stat instanceof AST_If) {
23766 stat.condition = cons_seq(stat.condition);
23767 }
23768 else if (stat instanceof AST_With) {
23769 stat.expression = cons_seq(stat.expression);
23770 }
23771 else if (stat instanceof AST_Exit && stat.value) {
23772 stat.value = cons_seq(stat.value);
23773 }
23774 else if (stat instanceof AST_Exit) {
23775 stat.value = cons_seq(make_node(AST_Undefined, stat));
23776 }
23777 else if (stat instanceof AST_Switch) {
23778 stat.expression = cons_seq(stat.expression);
23779 }
23780 }
23781 ret.push(stat);
23782 prev = stat instanceof AST_SimpleStatement ? stat : null;
23783 });
23784 return ret;
23785 };
23786
23787 function join_consecutive_vars(statements, compressor) {
23788 var prev = null;
23789 return statements.reduce(function(a, stat){
23790 if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
23791 prev.definitions = prev.definitions.concat(stat.definitions);
23792 CHANGED = true;
23793 }
23794 else if (stat instanceof AST_For
23795 && prev instanceof AST_Definitions
23796 && (!stat.init || stat.init.TYPE == prev.TYPE)) {
23797 CHANGED = true;
23798 a.pop();
23799 if (stat.init) {
23800 stat.init.definitions = prev.definitions.concat(stat.init.definitions);
23801 } else {
23802 stat.init = prev;
23803 }
23804 a.push(stat);
23805 prev = stat;
23806 }
23807 else {
23808 prev = stat;
23809 a.push(stat);
23810 }
23811 return a;
23812 }, []);
23813 };
23814
23815 function negate_iifes(statements, compressor) {
23816 statements.forEach(function(stat){
23817 if (stat instanceof AST_SimpleStatement) {
23818 stat.body = (function transform(thing) {
23819 return thing.transform(new TreeTransformer(function(node){
23820 if (node instanceof AST_Call && node.expression instanceof AST_Function) {
23821 return make_node(AST_UnaryPrefix, node, {
23822 operator: "!",
23823 expression: node
23824 });
23825 }
23826 else if (node instanceof AST_Call) {
23827 node.expression = transform(node.expression);
23828 }
23829 else if (node instanceof AST_Seq) {
23830 node.car = transform(node.car);
23831 }
23832 else if (node instanceof AST_Conditional) {
23833 var expr = transform(node.condition);
23834 if (expr !== node.condition) {
23835 // it has been negated, reverse
23836 node.condition = expr;
23837 var tmp = node.consequent;
23838 node.consequent = node.alternative;
23839 node.alternative = tmp;
23840 }
23841 }
23842 return node;
23843 }));
23844 })(stat.body);
23845 }
23846 });
23847 };
23848
23849 };
23850
23851 function extract_declarations_from_unreachable_code(compressor, stat, target) {
23852 compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
23853 stat.walk(new TreeWalker(function(node){
23854 if (node instanceof AST_Definitions) {
23855 compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
23856 node.remove_initializers();
23857 target.push(node);
23858 return true;
23859 }
23860 if (node instanceof AST_Defun) {
23861 target.push(node);
23862 return true;
23863 }
23864 if (node instanceof AST_Scope) {
23865 return true;
23866 }
23867 }));
23868 };
23869
23870 /* -----[ boolean/negation helpers ]----- */
23871
23872 // methods to determine whether an expression has a boolean result type
23873 (function (def){
23874 var unary_bool = [ "!", "delete" ];
23875 var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
23876 def(AST_Node, function(){ return false });
23877 def(AST_UnaryPrefix, function(){
23878 return member(this.operator, unary_bool);
23879 });
23880 def(AST_Binary, function(){
23881 return member(this.operator, binary_bool) ||
23882 ( (this.operator == "&&" || this.operator == "||") &&
23883 this.left.is_boolean() && this.right.is_boolean() );
23884 });
23885 def(AST_Conditional, function(){
23886 return this.consequent.is_boolean() && this.alternative.is_boolean();
23887 });
23888 def(AST_Assign, function(){
23889 return this.operator == "=" && this.right.is_boolean();
23890 });
23891 def(AST_Seq, function(){
23892 return this.cdr.is_boolean();
23893 });
23894 def(AST_True, function(){ return true });
23895 def(AST_False, function(){ return true });
23896 })(function(node, func){
23897 node.DEFMETHOD("is_boolean", func);
23898 });
23899
23900 // methods to determine if an expression has a string result type
23901 (function (def){
23902 def(AST_Node, function(){ return false });
23903 def(AST_String, function(){ return true });
23904 def(AST_UnaryPrefix, function(){
23905 return this.operator == "typeof";
23906 });
23907 def(AST_Binary, function(compressor){
23908 return this.operator == "+" &&
23909 (this.left.is_string(compressor) || this.right.is_string(compressor));
23910 });
23911 def(AST_Assign, function(compressor){
23912 return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
23913 });
23914 def(AST_Seq, function(compressor){
23915 return this.cdr.is_string(compressor);
23916 });
23917 def(AST_Conditional, function(compressor){
23918 return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
23919 });
23920 def(AST_Call, function(compressor){
23921 return compressor.option("unsafe")
23922 && this.expression instanceof AST_SymbolRef
23923 && this.expression.name == "String"
23924 && this.expression.undeclared();
23925 });
23926 })(function(node, func){
23927 node.DEFMETHOD("is_string", func);
23928 });
23929
23930 function best_of(ast1, ast2) {
23931 return ast1.print_to_string().length >
23932 ast2.print_to_string().length
23933 ? ast2 : ast1;
23934 };
23935
23936 // methods to evaluate a constant expression
23937 (function (def){
23938 // The evaluate method returns an array with one or two
23939 // elements. If the node has been successfully reduced to a
23940 // constant, then the second element tells us the value;
23941 // otherwise the second element is missing. The first element
23942 // of the array is always an AST_Node descendant; if
23943 // evaluation was successful it's a node that represents the
23944 // constant; otherwise it's the original or a replacement node.
23945 AST_Node.DEFMETHOD("evaluate", function(compressor){
23946 if (!compressor.option("evaluate")) return [ this ];
23947 try {
23948 var val = this._eval(compressor);
23949 return [ best_of(make_node_from_constant(compressor, val, this), this), val ];
23950 } catch(ex) {
23951 if (ex !== def) throw ex;
23952 return [ this ];
23953 }
23954 });
23955 def(AST_Statement, function(){
23956 throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
23957 });
23958 def(AST_Function, function(){
23959 // XXX: AST_Function inherits from AST_Scope, which itself
23960 // inherits from AST_Statement; however, an AST_Function
23961 // isn't really a statement. This could byte in other
23962 // places too. :-( Wish JS had multiple inheritance.
23963 throw def;
23964 });
23965 function ev(node, compressor) {
23966 if (!compressor) throw new Error("Compressor must be passed");
23967
23968 return node._eval(compressor);
23969 };
23970 def(AST_Node, function(){
23971 throw def; // not constant
23972 });
23973 def(AST_Constant, function(){
23974 return this.getValue();
23975 });
23976 def(AST_UnaryPrefix, function(compressor){
23977 var e = this.expression;
23978 switch (this.operator) {
23979 case "!": return !ev(e, compressor);
23980 case "typeof":
23981 // Function would be evaluated to an array and so typeof would
23982 // incorrectly return 'object'. Hence making is a special case.
23983 if (e instanceof AST_Function) return typeof function(){};
23984
23985 e = ev(e, compressor);
23986
23987 // typeof <RegExp> returns "object" or "function" on different platforms
23988 // so cannot evaluate reliably
23989 if (e instanceof RegExp) throw def;
23990
23991 return typeof e;
23992 case "void": return void ev(e, compressor);
23993 case "~": return ~ev(e, compressor);
23994 case "-":
23995 e = ev(e, compressor);
23996 if (e === 0) throw def;
23997 return -e;
23998 case "+": return +ev(e, compressor);
23999 }
24000 throw def;
24001 });
24002 def(AST_Binary, function(c){
24003 var left = this.left, right = this.right;
24004 switch (this.operator) {
24005 case "&&" : return ev(left, c) && ev(right, c);
24006 case "||" : return ev(left, c) || ev(right, c);
24007 case "|" : return ev(left, c) | ev(right, c);
24008 case "&" : return ev(left, c) & ev(right, c);
24009 case "^" : return ev(left, c) ^ ev(right, c);
24010 case "+" : return ev(left, c) + ev(right, c);
24011 case "*" : return ev(left, c) * ev(right, c);
24012 case "/" : return ev(left, c) / ev(right, c);
24013 case "%" : return ev(left, c) % ev(right, c);
24014 case "-" : return ev(left, c) - ev(right, c);
24015 case "<<" : return ev(left, c) << ev(right, c);
24016 case ">>" : return ev(left, c) >> ev(right, c);
24017 case ">>>" : return ev(left, c) >>> ev(right, c);
24018 case "==" : return ev(left, c) == ev(right, c);
24019 case "===" : return ev(left, c) === ev(right, c);
24020 case "!=" : return ev(left, c) != ev(right, c);
24021 case "!==" : return ev(left, c) !== ev(right, c);
24022 case "<" : return ev(left, c) < ev(right, c);
24023 case "<=" : return ev(left, c) <= ev(right, c);
24024 case ">" : return ev(left, c) > ev(right, c);
24025 case ">=" : return ev(left, c) >= ev(right, c);
24026 case "in" : return ev(left, c) in ev(right, c);
24027 case "instanceof" : return ev(left, c) instanceof ev(right, c);
24028 }
24029 throw def;
24030 });
24031 def(AST_Conditional, function(compressor){
24032 return ev(this.condition, compressor)
24033 ? ev(this.consequent, compressor)
24034 : ev(this.alternative, compressor);
24035 });
24036 def(AST_SymbolRef, function(compressor){
24037 var d = this.definition();
24038 if (d && d.constant && d.init) return ev(d.init, compressor);
24039 throw def;
24040 });
24041 def(AST_Dot, function(compressor){
24042 if (compressor.option("unsafe") && this.property == "length") {
24043 var str = ev(this.expression, compressor);
24044 if (typeof str == "string")
24045 return str.length;
24046 }
24047 throw def;
24048 });
24049 })(function(node, func){
24050 node.DEFMETHOD("_eval", func);
24051 });
24052
24053 // method to negate an expression
24054 (function(def){
24055 function basic_negation(exp) {
24056 return make_node(AST_UnaryPrefix, exp, {
24057 operator: "!",
24058 expression: exp
24059 });
24060 };
24061 def(AST_Node, function(){
24062 return basic_negation(this);
24063 });
24064 def(AST_Statement, function(){
24065 throw new Error("Cannot negate a statement");
24066 });
24067 def(AST_Function, function(){
24068 return basic_negation(this);
24069 });
24070 def(AST_UnaryPrefix, function(){
24071 if (this.operator == "!")
24072 return this.expression;
24073 return basic_negation(this);
24074 });
24075 def(AST_Seq, function(compressor){
24076 var self = this.clone();
24077 self.cdr = self.cdr.negate(compressor);
24078 return self;
24079 });
24080 def(AST_Conditional, function(compressor){
24081 var self = this.clone();
24082 self.consequent = self.consequent.negate(compressor);
24083 self.alternative = self.alternative.negate(compressor);
24084 return best_of(basic_negation(this), self);
24085 });
24086 def(AST_Binary, function(compressor){
24087 var self = this.clone(), op = this.operator;
24088 if (compressor.option("unsafe_comps")) {
24089 switch (op) {
24090 case "<=" : self.operator = ">" ; return self;
24091 case "<" : self.operator = ">=" ; return self;
24092 case ">=" : self.operator = "<" ; return self;
24093 case ">" : self.operator = "<=" ; return self;
24094 }
24095 }
24096 switch (op) {
24097 case "==" : self.operator = "!="; return self;
24098 case "!=" : self.operator = "=="; return self;
24099 case "===": self.operator = "!=="; return self;
24100 case "!==": self.operator = "==="; return self;
24101 case "&&":
24102 self.operator = "||";
24103 self.left = self.left.negate(compressor);
24104 self.right = self.right.negate(compressor);
24105 return best_of(basic_negation(this), self);
24106 case "||":
24107 self.operator = "&&";
24108 self.left = self.left.negate(compressor);
24109 self.right = self.right.negate(compressor);
24110 return best_of(basic_negation(this), self);
24111 }
24112 return basic_negation(this);
24113 });
24114 })(function(node, func){
24115 node.DEFMETHOD("negate", function(compressor){
24116 return func.call(this, compressor);
24117 });
24118 });
24119
24120 // determine if expression has side effects
24121 (function(def){
24122 def(AST_Node, function(compressor){ return true });
24123
24124 def(AST_EmptyStatement, function(compressor){ return false });
24125 def(AST_Constant, function(compressor){ return false });
24126 def(AST_This, function(compressor){ return false });
24127
24128 def(AST_Call, function(compressor){
24129 var pure = compressor.option("pure_funcs");
24130 if (!pure) return true;
24131 if (typeof pure == "function") return pure(this);
24132 return pure.indexOf(this.expression.print_to_string()) < 0;
24133 });
24134
24135 def(AST_Block, function(compressor){
24136 for (var i = this.body.length; --i >= 0;) {
24137 if (this.body[i].has_side_effects(compressor))
24138 return true;
24139 }
24140 return false;
24141 });
24142
24143 def(AST_SimpleStatement, function(compressor){
24144 return this.body.has_side_effects(compressor);
24145 });
24146 def(AST_Defun, function(compressor){ return true });
24147 def(AST_Function, function(compressor){ return false });
24148 def(AST_Binary, function(compressor){
24149 return this.left.has_side_effects(compressor)
24150 || this.right.has_side_effects(compressor);
24151 });
24152 def(AST_Assign, function(compressor){ return true });
24153 def(AST_Conditional, function(compressor){
24154 return this.condition.has_side_effects(compressor)
24155 || this.consequent.has_side_effects(compressor)
24156 || this.alternative.has_side_effects(compressor);
24157 });
24158 def(AST_Unary, function(compressor){
24159 return this.operator == "delete"
24160 || this.operator == "++"
24161 || this.operator == "--"
24162 || this.expression.has_side_effects(compressor);
24163 });
24164 def(AST_SymbolRef, function(compressor){
24165 return this.global() && this.undeclared();
24166 });
24167 def(AST_Object, function(compressor){
24168 for (var i = this.properties.length; --i >= 0;)
24169 if (this.properties[i].has_side_effects(compressor))
24170 return true;
24171 return false;
24172 });
24173 def(AST_ObjectProperty, function(compressor){
24174 return this.value.has_side_effects(compressor);
24175 });
24176 def(AST_Array, function(compressor){
24177 for (var i = this.elements.length; --i >= 0;)
24178 if (this.elements[i].has_side_effects(compressor))
24179 return true;
24180 return false;
24181 });
24182 def(AST_Dot, function(compressor){
24183 if (!compressor.option("pure_getters")) return true;
24184 return this.expression.has_side_effects(compressor);
24185 });
24186 def(AST_Sub, function(compressor){
24187 if (!compressor.option("pure_getters")) return true;
24188 return this.expression.has_side_effects(compressor)
24189 || this.property.has_side_effects(compressor);
24190 });
24191 def(AST_PropAccess, function(compressor){
24192 return !compressor.option("pure_getters");
24193 });
24194 def(AST_Seq, function(compressor){
24195 return this.car.has_side_effects(compressor)
24196 || this.cdr.has_side_effects(compressor);
24197 });
24198 })(function(node, func){
24199 node.DEFMETHOD("has_side_effects", func);
24200 });
24201
24202 // tell me if a statement aborts
24203 function aborts(thing) {
24204 return thing && thing.aborts();
24205 };
24206 (function(def){
24207 def(AST_Statement, function(){ return null });
24208 def(AST_Jump, function(){ return this });
24209 function block_aborts(){
24210 var n = this.body.length;
24211 return n > 0 && aborts(this.body[n - 1]);
24212 };
24213 def(AST_BlockStatement, block_aborts);
24214 def(AST_SwitchBranch, block_aborts);
24215 def(AST_If, function(){
24216 return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
24217 });
24218 })(function(node, func){
24219 node.DEFMETHOD("aborts", func);
24220 });
24221
24222 /* -----[ optimizers ]----- */
24223
24224 OPT(AST_Directive, function(self, compressor){
24225 if (compressor.has_directive(self.value) === "up") {
24226 return make_node(AST_EmptyStatement, self);
24227 }
24228 return self;
24229 });
24230
24231 OPT(AST_Debugger, function(self, compressor){
24232 if (compressor.option("drop_debugger"))
24233 return make_node(AST_EmptyStatement, self);
24234 return self;
24235 });
24236
24237 OPT(AST_LabeledStatement, function(self, compressor){
24238 if (self.body instanceof AST_Break
24239 && compressor.loopcontrol_target(self.body.label) === self.body) {
24240 return make_node(AST_EmptyStatement, self);
24241 }
24242 return self.label.references.length == 0 ? self.body : self;
24243 });
24244
24245 OPT(AST_Block, function(self, compressor){
24246 self.body = tighten_body(self.body, compressor);
24247 return self;
24248 });
24249
24250 OPT(AST_BlockStatement, function(self, compressor){
24251 self.body = tighten_body(self.body, compressor);
24252 switch (self.body.length) {
24253 case 1: return self.body[0];
24254 case 0: return make_node(AST_EmptyStatement, self);
24255 }
24256 return self;
24257 });
24258
24259 AST_Scope.DEFMETHOD("drop_unused", function(compressor){
24260 var self = this;
24261 if (compressor.has_directive("use asm")) return self;
24262 if (compressor.option("unused")
24263 && !(self instanceof AST_Toplevel)
24264 && !self.uses_eval
24265 ) {
24266 var in_use = [];
24267 var initializations = new Dictionary();
24268 // pass 1: find out which symbols are directly used in
24269 // this scope (not in nested scopes).
24270 var scope = this;
24271 var tw = new TreeWalker(function(node, descend){
24272 if (node !== self) {
24273 if (node instanceof AST_Defun) {
24274 initializations.add(node.name.name, node);
24275 return true; // don't go in nested scopes
24276 }
24277 if (node instanceof AST_Definitions && scope === self) {
24278 node.definitions.forEach(function(def){
24279 if (def.value) {
24280 initializations.add(def.name.name, def.value);
24281 if (def.value.has_side_effects(compressor)) {
24282 def.value.walk(tw);
24283 }
24284 }
24285 });
24286 return true;
24287 }
24288 if (node instanceof AST_SymbolRef) {
24289 push_uniq(in_use, node.definition());
24290 return true;
24291 }
24292 if (node instanceof AST_Scope) {
24293 var save_scope = scope;
24294 scope = node;
24295 descend();
24296 scope = save_scope;
24297 return true;
24298 }
24299 }
24300 });
24301 self.walk(tw);
24302 // pass 2: for every used symbol we need to walk its
24303 // initialization code to figure out if it uses other
24304 // symbols (that may not be in_use).
24305 for (var i = 0; i < in_use.length; ++i) {
24306 in_use[i].orig.forEach(function(decl){
24307 // undeclared globals will be instanceof AST_SymbolRef
24308 var init = initializations.get(decl.name);
24309 if (init) init.forEach(function(init){
24310 var tw = new TreeWalker(function(node){
24311 if (node instanceof AST_SymbolRef) {
24312 push_uniq(in_use, node.definition());
24313 }
24314 });
24315 init.walk(tw);
24316 });
24317 });
24318 }
24319 // pass 3: we should drop declarations not in_use
24320 var tt = new TreeTransformer(
24321 function before(node, descend, in_list) {
24322 if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
24323 if (!compressor.option("keep_fargs")) {
24324 for (var a = node.argnames, i = a.length; --i >= 0;) {
24325 var sym = a[i];
24326 if (sym.unreferenced()) {
24327 a.pop();
24328 compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
24329 name : sym.name,
24330 file : sym.start.file,
24331 line : sym.start.line,
24332 col : sym.start.col
24333 });
24334 }
24335 else break;
24336 }
24337 }
24338 }
24339 if (node instanceof AST_Defun && node !== self) {
24340 if (!member(node.name.definition(), in_use)) {
24341 compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
24342 name : node.name.name,
24343 file : node.name.start.file,
24344 line : node.name.start.line,
24345 col : node.name.start.col
24346 });
24347 return make_node(AST_EmptyStatement, node);
24348 }
24349 return node;
24350 }
24351 if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
24352 var def = node.definitions.filter(function(def){
24353 if (member(def.name.definition(), in_use)) return true;
24354 var w = {
24355 name : def.name.name,
24356 file : def.name.start.file,
24357 line : def.name.start.line,
24358 col : def.name.start.col
24359 };
24360 if (def.value && def.value.has_side_effects(compressor)) {
24361 def._unused_side_effects = true;
24362 compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
24363 return true;
24364 }
24365 compressor.warn("Dropping unused variable {name} [{file}:{line},{col}]", w);
24366 return false;
24367 });
24368 // place uninitialized names at the start
24369 def = mergeSort(def, function(a, b){
24370 if (!a.value && b.value) return -1;
24371 if (!b.value && a.value) return 1;
24372 return 0;
24373 });
24374 // for unused names whose initialization has
24375 // side effects, we can cascade the init. code
24376 // into the next one, or next statement.
24377 var side_effects = [];
24378 for (var i = 0; i < def.length;) {
24379 var x = def[i];
24380 if (x._unused_side_effects) {
24381 side_effects.push(x.value);
24382 def.splice(i, 1);
24383 } else {
24384 if (side_effects.length > 0) {
24385 side_effects.push(x.value);
24386 x.value = AST_Seq.from_array(side_effects);
24387 side_effects = [];
24388 }
24389 ++i;
24390 }
24391 }
24392 if (side_effects.length > 0) {
24393 side_effects = make_node(AST_BlockStatement, node, {
24394 body: [ make_node(AST_SimpleStatement, node, {
24395 body: AST_Seq.from_array(side_effects)
24396 }) ]
24397 });
24398 } else {
24399 side_effects = null;
24400 }
24401 if (def.length == 0 && !side_effects) {
24402 return make_node(AST_EmptyStatement, node);
24403 }
24404 if (def.length == 0) {
24405 return in_list ? MAP.splice(side_effects.body) : side_effects;
24406 }
24407 node.definitions = def;
24408 if (side_effects) {
24409 side_effects.body.unshift(node);
24410 return in_list ? MAP.splice(side_effects.body) : side_effects;
24411 }
24412 return node;
24413 }
24414 if (node instanceof AST_For) {
24415 descend(node, this);
24416
24417 if (node.init instanceof AST_BlockStatement) {
24418 // certain combination of unused name + side effect leads to:
24419 // https://github.com/mishoo/UglifyJS2/issues/44
24420 // that's an invalid AST.
24421 // We fix it at this stage by moving the `var` outside the `for`.
24422
24423 var body = node.init.body.slice(0, -1);
24424 node.init = node.init.body.slice(-1)[0].body;
24425 body.push(node);
24426
24427 return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
24428 body: body
24429 });
24430 }
24431 }
24432 if (node instanceof AST_Scope && node !== self)
24433 return node;
24434 }
24435 );
24436 self.transform(tt);
24437 }
24438 });
24439
24440 AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
24441 var self = this;
24442 if (compressor.has_directive("use asm")) return self;
24443 var hoist_funs = compressor.option("hoist_funs");
24444 var hoist_vars = compressor.option("hoist_vars");
24445 if (hoist_funs || hoist_vars) {
24446 var dirs = [];
24447 var hoisted = [];
24448 var vars = new Dictionary(), vars_found = 0, var_decl = 0;
24449 // let's count var_decl first, we seem to waste a lot of
24450 // space if we hoist `var` when there's only one.
24451 self.walk(new TreeWalker(function(node){
24452 if (node instanceof AST_Scope && node !== self)
24453 return true;
24454 if (node instanceof AST_Var) {
24455 ++var_decl;
24456 return true;
24457 }
24458 }));
24459 hoist_vars = hoist_vars && var_decl > 1;
24460 var tt = new TreeTransformer(
24461 function before(node) {
24462 if (node !== self) {
24463 if (node instanceof AST_Directive) {
24464 dirs.push(node);
24465 return make_node(AST_EmptyStatement, node);
24466 }
24467 if (node instanceof AST_Defun && hoist_funs) {
24468 hoisted.push(node);
24469 return make_node(AST_EmptyStatement, node);
24470 }
24471 if (node instanceof AST_Var && hoist_vars) {
24472 node.definitions.forEach(function(def){
24473 vars.set(def.name.name, def);
24474 ++vars_found;
24475 });
24476 var seq = node.to_assignments();
24477 var p = tt.parent();
24478 if (p instanceof AST_ForIn && p.init === node) {
24479 if (seq == null) return node.definitions[0].name;
24480 return seq;
24481 }
24482 if (p instanceof AST_For && p.init === node) {
24483 return seq;
24484 }
24485 if (!seq) return make_node(AST_EmptyStatement, node);
24486 return make_node(AST_SimpleStatement, node, {
24487 body: seq
24488 });
24489 }
24490 if (node instanceof AST_Scope)
24491 return node; // to avoid descending in nested scopes
24492 }
24493 }
24494 );
24495 self = self.transform(tt);
24496 if (vars_found > 0) {
24497 // collect only vars which don't show up in self's arguments list
24498 var defs = [];
24499 vars.each(function(def, name){
24500 if (self instanceof AST_Lambda
24501 && find_if(function(x){ return x.name == def.name.name },
24502 self.argnames)) {
24503 vars.del(name);
24504 } else {
24505 def = def.clone();
24506 def.value = null;
24507 defs.push(def);
24508 vars.set(name, def);
24509 }
24510 });
24511 if (defs.length > 0) {
24512 // try to merge in assignments
24513 for (var i = 0; i < self.body.length;) {
24514 if (self.body[i] instanceof AST_SimpleStatement) {
24515 var expr = self.body[i].body, sym, assign;
24516 if (expr instanceof AST_Assign
24517 && expr.operator == "="
24518 && (sym = expr.left) instanceof AST_Symbol
24519 && vars.has(sym.name))
24520 {
24521 var def = vars.get(sym.name);
24522 if (def.value) break;
24523 def.value = expr.right;
24524 remove(defs, def);
24525 defs.push(def);
24526 self.body.splice(i, 1);
24527 continue;
24528 }
24529 if (expr instanceof AST_Seq
24530 && (assign = expr.car) instanceof AST_Assign
24531 && assign.operator == "="
24532 && (sym = assign.left) instanceof AST_Symbol
24533 && vars.has(sym.name))
24534 {
24535 var def = vars.get(sym.name);
24536 if (def.value) break;
24537 def.value = assign.right;
24538 remove(defs, def);
24539 defs.push(def);
24540 self.body[i].body = expr.cdr;
24541 continue;
24542 }
24543 }
24544 if (self.body[i] instanceof AST_EmptyStatement) {
24545 self.body.splice(i, 1);
24546 continue;
24547 }
24548 if (self.body[i] instanceof AST_BlockStatement) {
24549 var tmp = [ i, 1 ].concat(self.body[i].body);
24550 self.body.splice.apply(self.body, tmp);
24551 continue;
24552 }
24553 break;
24554 }
24555 defs = make_node(AST_Var, self, {
24556 definitions: defs
24557 });
24558 hoisted.push(defs);
24559 };
24560 }
24561 self.body = dirs.concat(hoisted, self.body);
24562 }
24563 return self;
24564 });
24565
24566 OPT(AST_SimpleStatement, function(self, compressor){
24567 if (compressor.option("side_effects")) {
24568 if (!self.body.has_side_effects(compressor)) {
24569 compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
24570 return make_node(AST_EmptyStatement, self);
24571 }
24572 }
24573 return self;
24574 });
24575
24576 OPT(AST_DWLoop, function(self, compressor){
24577 var cond = self.condition.evaluate(compressor);
24578 self.condition = cond[0];
24579 if (!compressor.option("loops")) return self;
24580 if (cond.length > 1) {
24581 if (cond[1]) {
24582 return make_node(AST_For, self, {
24583 body: self.body
24584 });
24585 } else if (self instanceof AST_While) {
24586 if (compressor.option("dead_code")) {
24587 var a = [];
24588 extract_declarations_from_unreachable_code(compressor, self.body, a);
24589 return make_node(AST_BlockStatement, self, { body: a });
24590 }
24591 }
24592 }
24593 return self;
24594 });
24595
24596 function if_break_in_loop(self, compressor) {
24597 function drop_it(rest) {
24598 rest = as_statement_array(rest);
24599 if (self.body instanceof AST_BlockStatement) {
24600 self.body = self.body.clone();
24601 self.body.body = rest.concat(self.body.body.slice(1));
24602 self.body = self.body.transform(compressor);
24603 } else {
24604 self.body = make_node(AST_BlockStatement, self.body, {
24605 body: rest
24606 }).transform(compressor);
24607 }
24608 if_break_in_loop(self, compressor);
24609 }
24610 var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
24611 if (first instanceof AST_If) {
24612 if (first.body instanceof AST_Break
24613 && compressor.loopcontrol_target(first.body.label) === self) {
24614 if (self.condition) {
24615 self.condition = make_node(AST_Binary, self.condition, {
24616 left: self.condition,
24617 operator: "&&",
24618 right: first.condition.negate(compressor),
24619 });
24620 } else {
24621 self.condition = first.condition.negate(compressor);
24622 }
24623 drop_it(first.alternative);
24624 }
24625 else if (first.alternative instanceof AST_Break
24626 && compressor.loopcontrol_target(first.alternative.label) === self) {
24627 if (self.condition) {
24628 self.condition = make_node(AST_Binary, self.condition, {
24629 left: self.condition,
24630 operator: "&&",
24631 right: first.condition,
24632 });
24633 } else {
24634 self.condition = first.condition;
24635 }
24636 drop_it(first.body);
24637 }
24638 }
24639 };
24640
24641 OPT(AST_While, function(self, compressor) {
24642 if (!compressor.option("loops")) return self;
24643 self = AST_DWLoop.prototype.optimize.call(self, compressor);
24644 if (self instanceof AST_While) {
24645 if_break_in_loop(self, compressor);
24646 self = make_node(AST_For, self, self).transform(compressor);
24647 }
24648 return self;
24649 });
24650
24651 OPT(AST_For, function(self, compressor){
24652 var cond = self.condition;
24653 if (cond) {
24654 cond = cond.evaluate(compressor);
24655 self.condition = cond[0];
24656 }
24657 if (!compressor.option("loops")) return self;
24658 if (cond) {
24659 if (cond.length > 1 && !cond[1]) {
24660 if (compressor.option("dead_code")) {
24661 var a = [];
24662 if (self.init instanceof AST_Statement) {
24663 a.push(self.init);
24664 }
24665 else if (self.init) {
24666 a.push(make_node(AST_SimpleStatement, self.init, {
24667 body: self.init
24668 }));
24669 }
24670 extract_declarations_from_unreachable_code(compressor, self.body, a);
24671 return make_node(AST_BlockStatement, self, { body: a });
24672 }
24673 }
24674 }
24675 if_break_in_loop(self, compressor);
24676 return self;
24677 });
24678
24679 OPT(AST_If, function(self, compressor){
24680 if (!compressor.option("conditionals")) return self;
24681 // if condition can be statically determined, warn and drop
24682 // one of the blocks. note, statically determined implies
24683 // “has no side effects”; also it doesn't work for cases like
24684 // `x && true`, though it probably should.
24685 var cond = self.condition.evaluate(compressor);
24686 self.condition = cond[0];
24687 if (cond.length > 1) {
24688 if (cond[1]) {
24689 compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
24690 if (compressor.option("dead_code")) {
24691 var a = [];
24692 if (self.alternative) {
24693 extract_declarations_from_unreachable_code(compressor, self.alternative, a);
24694 }
24695 a.push(self.body);
24696 return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
24697 }
24698 } else {
24699 compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
24700 if (compressor.option("dead_code")) {
24701 var a = [];
24702 extract_declarations_from_unreachable_code(compressor, self.body, a);
24703 if (self.alternative) a.push(self.alternative);
24704 return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
24705 }
24706 }
24707 }
24708 if (is_empty(self.alternative)) self.alternative = null;
24709 var negated = self.condition.negate(compressor);
24710 var negated_is_best = best_of(self.condition, negated) === negated;
24711 if (self.alternative && negated_is_best) {
24712 negated_is_best = false; // because we already do the switch here.
24713 self.condition = negated;
24714 var tmp = self.body;
24715 self.body = self.alternative || make_node(AST_EmptyStatement);
24716 self.alternative = tmp;
24717 }
24718 if (is_empty(self.body) && is_empty(self.alternative)) {
24719 return make_node(AST_SimpleStatement, self.condition, {
24720 body: self.condition
24721 }).transform(compressor);
24722 }
24723 if (self.body instanceof AST_SimpleStatement
24724 && self.alternative instanceof AST_SimpleStatement) {
24725 return make_node(AST_SimpleStatement, self, {
24726 body: make_node(AST_Conditional, self, {
24727 condition : self.condition,
24728 consequent : self.body.body,
24729 alternative : self.alternative.body
24730 })
24731 }).transform(compressor);
24732 }
24733 if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
24734 if (negated_is_best) return make_node(AST_SimpleStatement, self, {
24735 body: make_node(AST_Binary, self, {
24736 operator : "||",
24737 left : negated,
24738 right : self.body.body
24739 })
24740 }).transform(compressor);
24741 return make_node(AST_SimpleStatement, self, {
24742 body: make_node(AST_Binary, self, {
24743 operator : "&&",
24744 left : self.condition,
24745 right : self.body.body
24746 })
24747 }).transform(compressor);
24748 }
24749 if (self.body instanceof AST_EmptyStatement
24750 && self.alternative
24751 && self.alternative instanceof AST_SimpleStatement) {
24752 return make_node(AST_SimpleStatement, self, {
24753 body: make_node(AST_Binary, self, {
24754 operator : "||",
24755 left : self.condition,
24756 right : self.alternative.body
24757 })
24758 }).transform(compressor);
24759 }
24760 if (self.body instanceof AST_Exit
24761 && self.alternative instanceof AST_Exit
24762 && self.body.TYPE == self.alternative.TYPE) {
24763 return make_node(self.body.CTOR, self, {
24764 value: make_node(AST_Conditional, self, {
24765 condition : self.condition,
24766 consequent : self.body.value || make_node(AST_Undefined, self.body).optimize(compressor),
24767 alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).optimize(compressor)
24768 })
24769 }).transform(compressor);
24770 }
24771 if (self.body instanceof AST_If
24772 && !self.body.alternative
24773 && !self.alternative) {
24774 self.condition = make_node(AST_Binary, self.condition, {
24775 operator: "&&",
24776 left: self.condition,
24777 right: self.body.condition
24778 }).transform(compressor);
24779 self.body = self.body.body;
24780 }
24781 if (aborts(self.body)) {
24782 if (self.alternative) {
24783 var alt = self.alternative;
24784 self.alternative = null;
24785 return make_node(AST_BlockStatement, self, {
24786 body: [ self, alt ]
24787 }).transform(compressor);
24788 }
24789 }
24790 if (aborts(self.alternative)) {
24791 var body = self.body;
24792 self.body = self.alternative;
24793 self.condition = negated_is_best ? negated : self.condition.negate(compressor);
24794 self.alternative = null;
24795 return make_node(AST_BlockStatement, self, {
24796 body: [ self, body ]
24797 }).transform(compressor);
24798 }
24799 return self;
24800 });
24801
24802 OPT(AST_Switch, function(self, compressor){
24803 if (self.body.length == 0 && compressor.option("conditionals")) {
24804 return make_node(AST_SimpleStatement, self, {
24805 body: self.expression
24806 }).transform(compressor);
24807 }
24808 for(;;) {
24809 var last_branch = self.body[self.body.length - 1];
24810 if (last_branch) {
24811 var stat = last_branch.body[last_branch.body.length - 1]; // last statement
24812 if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
24813 last_branch.body.pop();
24814 if (last_branch instanceof AST_Default && last_branch.body.length == 0) {
24815 self.body.pop();
24816 continue;
24817 }
24818 }
24819 break;
24820 }
24821 var exp = self.expression.evaluate(compressor);
24822 out: if (exp.length == 2) try {
24823 // constant expression
24824 self.expression = exp[0];
24825 if (!compressor.option("dead_code")) break out;
24826 var value = exp[1];
24827 var in_if = false;
24828 var in_block = false;
24829 var started = false;
24830 var stopped = false;
24831 var ruined = false;
24832 var tt = new TreeTransformer(function(node, descend, in_list){
24833 if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
24834 // no need to descend these node types
24835 return node;
24836 }
24837 else if (node instanceof AST_Switch && node === self) {
24838 node = node.clone();
24839 descend(node, this);
24840 return ruined ? node : make_node(AST_BlockStatement, node, {
24841 body: node.body.reduce(function(a, branch){
24842 return a.concat(branch.body);
24843 }, [])
24844 }).transform(compressor);
24845 }
24846 else if (node instanceof AST_If || node instanceof AST_Try) {
24847 var save = in_if;
24848 in_if = !in_block;
24849 descend(node, this);
24850 in_if = save;
24851 return node;
24852 }
24853 else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch) {
24854 var save = in_block;
24855 in_block = true;
24856 descend(node, this);
24857 in_block = save;
24858 return node;
24859 }
24860 else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
24861 if (in_if) {
24862 ruined = true;
24863 return node;
24864 }
24865 if (in_block) return node;
24866 stopped = true;
24867 return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
24868 }
24869 else if (node instanceof AST_SwitchBranch && this.parent() === self) {
24870 if (stopped) return MAP.skip;
24871 if (node instanceof AST_Case) {
24872 var exp = node.expression.evaluate(compressor);
24873 if (exp.length < 2) {
24874 // got a case with non-constant expression, baling out
24875 throw self;
24876 }
24877 if (exp[1] === value || started) {
24878 started = true;
24879 if (aborts(node)) stopped = true;
24880 descend(node, this);
24881 return node;
24882 }
24883 return MAP.skip;
24884 }
24885 descend(node, this);
24886 return node;
24887 }
24888 });
24889 tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
24890 self = self.transform(tt);
24891 } catch(ex) {
24892 if (ex !== self) throw ex;
24893 }
24894 return self;
24895 });
24896
24897 OPT(AST_Case, function(self, compressor){
24898 self.body = tighten_body(self.body, compressor);
24899 return self;
24900 });
24901
24902 OPT(AST_Try, function(self, compressor){
24903 self.body = tighten_body(self.body, compressor);
24904 return self;
24905 });
24906
24907 AST_Definitions.DEFMETHOD("remove_initializers", function(){
24908 this.definitions.forEach(function(def){ def.value = null });
24909 });
24910
24911 AST_Definitions.DEFMETHOD("to_assignments", function(){
24912 var assignments = this.definitions.reduce(function(a, def){
24913 if (def.value) {
24914 var name = make_node(AST_SymbolRef, def.name, def.name);
24915 a.push(make_node(AST_Assign, def, {
24916 operator : "=",
24917 left : name,
24918 right : def.value
24919 }));
24920 }
24921 return a;
24922 }, []);
24923 if (assignments.length == 0) return null;
24924 return AST_Seq.from_array(assignments);
24925 });
24926
24927 OPT(AST_Definitions, function(self, compressor){
24928 if (self.definitions.length == 0)
24929 return make_node(AST_EmptyStatement, self);
24930 return self;
24931 });
24932
24933 OPT(AST_Function, function(self, compressor){
24934 self = AST_Lambda.prototype.optimize.call(self, compressor);
24935 if (compressor.option("unused") && !compressor.option("keep_fnames")) {
24936 if (self.name && self.name.unreferenced()) {
24937 self.name = null;
24938 }
24939 }
24940 return self;
24941 });
24942
24943 OPT(AST_Call, function(self, compressor){
24944 if (compressor.option("unsafe")) {
24945 var exp = self.expression;
24946 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
24947 switch (exp.name) {
24948 case "Array":
24949 if (self.args.length != 1) {
24950 return make_node(AST_Array, self, {
24951 elements: self.args
24952 }).transform(compressor);
24953 }
24954 break;
24955 case "Object":
24956 if (self.args.length == 0) {
24957 return make_node(AST_Object, self, {
24958 properties: []
24959 });
24960 }
24961 break;
24962 case "String":
24963 if (self.args.length == 0) return make_node(AST_String, self, {
24964 value: ""
24965 });
24966 if (self.args.length <= 1) return make_node(AST_Binary, self, {
24967 left: self.args[0],
24968 operator: "+",
24969 right: make_node(AST_String, self, { value: "" })
24970 }).transform(compressor);
24971 break;
24972 case "Number":
24973 if (self.args.length == 0) return make_node(AST_Number, self, {
24974 value: 0
24975 });
24976 if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
24977 expression: self.args[0],
24978 operator: "+"
24979 }).transform(compressor);
24980 case "Boolean":
24981 if (self.args.length == 0) return make_node(AST_False, self);
24982 if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
24983 expression: make_node(AST_UnaryPrefix, null, {
24984 expression: self.args[0],
24985 operator: "!"
24986 }),
24987 operator: "!"
24988 }).transform(compressor);
24989 break;
24990 case "Function":
24991 // new Function() => function(){}
24992 if (self.args.length == 0) return make_node(AST_Function, self, {
24993 argnames: [],
24994 body: []
24995 });
24996 if (all(self.args, function(x){ return x instanceof AST_String })) {
24997 // quite a corner-case, but we can handle it:
24998 // https://github.com/mishoo/UglifyJS2/issues/203
24999 // if the code argument is a constant, then we can minify it.
25000 try {
25001 var code = "(function(" + self.args.slice(0, -1).map(function(arg){
25002 return arg.value;
25003 }).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
25004 var ast = parse(code);
25005 ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
25006 var comp = new Compressor(compressor.options);
25007 ast = ast.transform(comp);
25008 ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") });
25009 ast.mangle_names();
25010 var fun;
25011 try {
25012 ast.walk(new TreeWalker(function(node){
25013 if (node instanceof AST_Lambda) {
25014 fun = node;
25015 throw ast;
25016 }
25017 }));
25018 } catch(ex) {
25019 if (ex !== ast) throw ex;
25020 };
25021 if (!fun) return self;
25022 var args = fun.argnames.map(function(arg, i){
25023 return make_node(AST_String, self.args[i], {
25024 value: arg.print_to_string()
25025 });
25026 });
25027 var code = OutputStream();
25028 AST_BlockStatement.prototype._codegen.call(fun, fun, code);
25029 code = code.toString().replace(/^\{|\}$/g, "");
25030 args.push(make_node(AST_String, self.args[self.args.length - 1], {
25031 value: code
25032 }));
25033 self.args = args;
25034 return self;
25035 } catch(ex) {
25036 if (ex instanceof JS_Parse_Error) {
25037 compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
25038 compressor.warn(ex.toString());
25039 } else {
25040 console.log(ex);
25041 throw ex;
25042 }
25043 }
25044 }
25045 break;
25046 }
25047 }
25048 else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
25049 return make_node(AST_Binary, self, {
25050 left: make_node(AST_String, self, { value: "" }),
25051 operator: "+",
25052 right: exp.expression
25053 }).transform(compressor);
25054 }
25055 else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: {
25056 var separator = self.args.length == 0 ? "," : self.args[0].evaluate(compressor)[1];
25057 if (separator == null) break EXIT; // not a constant
25058 var elements = exp.expression.elements.reduce(function(a, el){
25059 el = el.evaluate(compressor);
25060 if (a.length == 0 || el.length == 1) {
25061 a.push(el);
25062 } else {
25063 var last = a[a.length - 1];
25064 if (last.length == 2) {
25065 // it's a constant
25066 var val = "" + last[1] + separator + el[1];
25067 a[a.length - 1] = [ make_node_from_constant(compressor, val, last[0]), val ];
25068 } else {
25069 a.push(el);
25070 }
25071 }
25072 return a;
25073 }, []);
25074 if (elements.length == 0) return make_node(AST_String, self, { value: "" });
25075 if (elements.length == 1) return elements[0][0];
25076 if (separator == "") {
25077 var first;
25078 if (elements[0][0] instanceof AST_String
25079 || elements[1][0] instanceof AST_String) {
25080 first = elements.shift()[0];
25081 } else {
25082 first = make_node(AST_String, self, { value: "" });
25083 }
25084 return elements.reduce(function(prev, el){
25085 return make_node(AST_Binary, el[0], {
25086 operator : "+",
25087 left : prev,
25088 right : el[0],
25089 });
25090 }, first).transform(compressor);
25091 }
25092 // need this awkward cloning to not affect original element
25093 // best_of will decide which one to get through.
25094 var node = self.clone();
25095 node.expression = node.expression.clone();
25096 node.expression.expression = node.expression.expression.clone();
25097 node.expression.expression.elements = elements.map(function(el){
25098 return el[0];
25099 });
25100 return best_of(self, node);
25101 }
25102 }
25103 if (compressor.option("side_effects")) {
25104 if (self.expression instanceof AST_Function
25105 && self.args.length == 0
25106 && !AST_Block.prototype.has_side_effects.call(self.expression, compressor)) {
25107 return make_node(AST_Undefined, self).transform(compressor);
25108 }
25109 }
25110 if (compressor.option("drop_console")) {
25111 if (self.expression instanceof AST_PropAccess) {
25112 var name = self.expression.expression;
25113 while (name.expression) {
25114 name = name.expression;
25115 }
25116 if (name instanceof AST_SymbolRef
25117 && name.name == "console"
25118 && name.undeclared()) {
25119 return make_node(AST_Undefined, self).transform(compressor);
25120 }
25121 }
25122 }
25123 return self.evaluate(compressor)[0];
25124 });
25125
25126 OPT(AST_New, function(self, compressor){
25127 if (compressor.option("unsafe")) {
25128 var exp = self.expression;
25129 if (exp instanceof AST_SymbolRef && exp.undeclared()) {
25130 switch (exp.name) {
25131 case "Object":
25132 case "RegExp":
25133 case "Function":
25134 case "Error":
25135 case "Array":
25136 return make_node(AST_Call, self, self).transform(compressor);
25137 }
25138 }
25139 }
25140 return self;
25141 });
25142
25143 OPT(AST_Seq, function(self, compressor){
25144 if (!compressor.option("side_effects"))
25145 return self;
25146 if (!self.car.has_side_effects(compressor)) {
25147 // we shouldn't compress (1,func)(something) to
25148 // func(something) because that changes the meaning of
25149 // the func (becomes lexical instead of global).
25150 var p = compressor.parent();
25151 if (!(p instanceof AST_Call && p.expression === self)) {
25152 return self.cdr;
25153 }
25154 }
25155 if (compressor.option("cascade")) {
25156 if (self.car instanceof AST_Assign
25157 && !self.car.left.has_side_effects(compressor)) {
25158 if (self.car.left.equivalent_to(self.cdr)) {
25159 return self.car;
25160 }
25161 if (self.cdr instanceof AST_Call
25162 && self.cdr.expression.equivalent_to(self.car.left)) {
25163 self.cdr.expression = self.car;
25164 return self.cdr;
25165 }
25166 }
25167 if (!self.car.has_side_effects(compressor)
25168 && !self.cdr.has_side_effects(compressor)
25169 && self.car.equivalent_to(self.cdr)) {
25170 return self.car;
25171 }
25172 }
25173 if (self.cdr instanceof AST_UnaryPrefix
25174 && self.cdr.operator == "void"
25175 && !self.cdr.expression.has_side_effects(compressor)) {
25176 self.cdr.expression = self.car;
25177 return self.cdr;
25178 }
25179 if (self.cdr instanceof AST_Undefined) {
25180 return make_node(AST_UnaryPrefix, self, {
25181 operator : "void",
25182 expression : self.car
25183 });
25184 }
25185 return self;
25186 });
25187
25188 AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
25189 if (compressor.option("sequences")) {
25190 if (this.expression instanceof AST_Seq) {
25191 var seq = this.expression;
25192 var x = seq.to_array();
25193 this.expression = x.pop();
25194 x.push(this);
25195 seq = AST_Seq.from_array(x).transform(compressor);
25196 return seq;
25197 }
25198 }
25199 return this;
25200 });
25201
25202 OPT(AST_UnaryPostfix, function(self, compressor){
25203 return self.lift_sequences(compressor);
25204 });
25205
25206 OPT(AST_UnaryPrefix, function(self, compressor){
25207 self = self.lift_sequences(compressor);
25208 var e = self.expression;
25209 if (compressor.option("booleans") && compressor.in_boolean_context()) {
25210 switch (self.operator) {
25211 case "!":
25212 if (e instanceof AST_UnaryPrefix && e.operator == "!") {
25213 // !!foo ==> foo, if we're in boolean context
25214 return e.expression;
25215 }
25216 break;
25217 case "typeof":
25218 // typeof always returns a non-empty string, thus it's
25219 // always true in booleans
25220 compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
25221 return make_node(AST_True, self);
25222 }
25223 if (e instanceof AST_Binary && self.operator == "!") {
25224 self = best_of(self, e.negate(compressor));
25225 }
25226 }
25227 return self.evaluate(compressor)[0];
25228 });
25229
25230 function has_side_effects_or_prop_access(node, compressor) {
25231 var save_pure_getters = compressor.option("pure_getters");
25232 compressor.options.pure_getters = false;
25233 var ret = node.has_side_effects(compressor);
25234 compressor.options.pure_getters = save_pure_getters;
25235 return ret;
25236 }
25237
25238 AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
25239 if (compressor.option("sequences")) {
25240 if (this.left instanceof AST_Seq) {
25241 var seq = this.left;
25242 var x = seq.to_array();
25243 this.left = x.pop();
25244 x.push(this);
25245 seq = AST_Seq.from_array(x).transform(compressor);
25246 return seq;
25247 }
25248 if (this.right instanceof AST_Seq
25249 && this instanceof AST_Assign
25250 && !has_side_effects_or_prop_access(this.left, compressor)) {
25251 var seq = this.right;
25252 var x = seq.to_array();
25253 this.right = x.pop();
25254 x.push(this);
25255 seq = AST_Seq.from_array(x).transform(compressor);
25256 return seq;
25257 }
25258 }
25259 return this;
25260 });
25261
25262 var commutativeOperators = makePredicate("== === != !== * & | ^");
25263
25264 OPT(AST_Binary, function(self, compressor){
25265 function reverse(op, force) {
25266 if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
25267 if (op) self.operator = op;
25268 var tmp = self.left;
25269 self.left = self.right;
25270 self.right = tmp;
25271 }
25272 }
25273 if (commutativeOperators(self.operator)) {
25274 if (self.right instanceof AST_Constant
25275 && !(self.left instanceof AST_Constant)) {
25276 // if right is a constant, whatever side effects the
25277 // left side might have could not influence the
25278 // result. hence, force switch.
25279
25280 if (!(self.left instanceof AST_Binary
25281 && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
25282 reverse(null, true);
25283 }
25284 }
25285 if (/^[!=]==?$/.test(self.operator)) {
25286 if (self.left instanceof AST_SymbolRef && self.right instanceof AST_Conditional) {
25287 if (self.right.consequent instanceof AST_SymbolRef
25288 && self.right.consequent.definition() === self.left.definition()) {
25289 if (/^==/.test(self.operator)) return self.right.condition;
25290 if (/^!=/.test(self.operator)) return self.right.condition.negate(compressor);
25291 }
25292 if (self.right.alternative instanceof AST_SymbolRef
25293 && self.right.alternative.definition() === self.left.definition()) {
25294 if (/^==/.test(self.operator)) return self.right.condition.negate(compressor);
25295 if (/^!=/.test(self.operator)) return self.right.condition;
25296 }
25297 }
25298 if (self.right instanceof AST_SymbolRef && self.left instanceof AST_Conditional) {
25299 if (self.left.consequent instanceof AST_SymbolRef
25300 && self.left.consequent.definition() === self.right.definition()) {
25301 if (/^==/.test(self.operator)) return self.left.condition;
25302 if (/^!=/.test(self.operator)) return self.left.condition.negate(compressor);
25303 }
25304 if (self.left.alternative instanceof AST_SymbolRef
25305 && self.left.alternative.definition() === self.right.definition()) {
25306 if (/^==/.test(self.operator)) return self.left.condition.negate(compressor);
25307 if (/^!=/.test(self.operator)) return self.left.condition;
25308 }
25309 }
25310 }
25311 }
25312 self = self.lift_sequences(compressor);
25313 if (compressor.option("comparisons")) switch (self.operator) {
25314 case "===":
25315 case "!==":
25316 if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
25317 (self.left.is_boolean() && self.right.is_boolean())) {
25318 self.operator = self.operator.substr(0, 2);
25319 }
25320 // XXX: intentionally falling down to the next case
25321 case "==":
25322 case "!=":
25323 if (self.left instanceof AST_String
25324 && self.left.value == "undefined"
25325 && self.right instanceof AST_UnaryPrefix
25326 && self.right.operator == "typeof"
25327 && compressor.option("unsafe")) {
25328 if (!(self.right.expression instanceof AST_SymbolRef)
25329 || !self.right.expression.undeclared()) {
25330 self.right = self.right.expression;
25331 self.left = make_node(AST_Undefined, self.left).optimize(compressor);
25332 if (self.operator.length == 2) self.operator += "=";
25333 }
25334 }
25335 break;
25336 }
25337 if (compressor.option("conditionals")) {
25338 if (self.operator == "&&") {
25339 var ll = self.left.evaluate(compressor);
25340 if (ll.length > 1) {
25341 if (ll[1]) {
25342 compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
25343 var rr = self.right.evaluate(compressor);
25344 return rr[0];
25345 } else {
25346 compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
25347 return ll[0];
25348 }
25349 }
25350 }
25351 else if (self.operator == "||") {
25352 var ll = self.left.evaluate(compressor);
25353 if (ll.length > 1) {
25354 if (ll[1]) {
25355 compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
25356 return ll[0];
25357 } else {
25358 compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
25359 var rr = self.right.evaluate(compressor);
25360 return rr[0];
25361 }
25362 }
25363 }
25364 }
25365 if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
25366 case "&&":
25367 var ll = self.left.evaluate(compressor);
25368 var rr = self.right.evaluate(compressor);
25369 if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
25370 compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
25371 if (self.left.has_side_effects(compressor)) {
25372 return make_node(AST_Seq, self, {
25373 car: self.left,
25374 cdr: make_node(AST_False)
25375 }).optimize(compressor);
25376 }
25377 return make_node(AST_False, self);
25378 }
25379 if (ll.length > 1 && ll[1]) {
25380 return rr[0];
25381 }
25382 if (rr.length > 1 && rr[1]) {
25383 return ll[0];
25384 }
25385 break;
25386 case "||":
25387 var ll = self.left.evaluate(compressor);
25388 var rr = self.right.evaluate(compressor);
25389 if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
25390 compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
25391 if (self.left.has_side_effects(compressor)) {
25392 return make_node(AST_Seq, self, {
25393 car: self.left,
25394 cdr: make_node(AST_True)
25395 }).optimize(compressor);
25396 }
25397 return make_node(AST_True, self);
25398 }
25399 if (ll.length > 1 && !ll[1]) {
25400 return rr[0];
25401 }
25402 if (rr.length > 1 && !rr[1]) {
25403 return ll[0];
25404 }
25405 break;
25406 case "+":
25407 var ll = self.left.evaluate(compressor);
25408 var rr = self.right.evaluate(compressor);
25409 if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||
25410 (rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {
25411 compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
25412 return make_node(AST_True, self);
25413 }
25414 break;
25415 }
25416 if (compressor.option("comparisons") && self.is_boolean()) {
25417 if (!(compressor.parent() instanceof AST_Binary)
25418 || compressor.parent() instanceof AST_Assign) {
25419 var negated = make_node(AST_UnaryPrefix, self, {
25420 operator: "!",
25421 expression: self.negate(compressor)
25422 });
25423 self = best_of(self, negated);
25424 }
25425 switch (self.operator) {
25426 case "<": reverse(">"); break;
25427 case "<=": reverse(">="); break;
25428 }
25429 }
25430 if (self.operator == "+" && self.right instanceof AST_String
25431 && self.right.getValue() === "" && self.left instanceof AST_Binary
25432 && self.left.operator == "+" && self.left.is_string(compressor)) {
25433 return self.left;
25434 }
25435 if (compressor.option("evaluate")) {
25436 if (self.operator == "+") {
25437 if (self.left instanceof AST_Constant
25438 && self.right instanceof AST_Binary
25439 && self.right.operator == "+"
25440 && self.right.left instanceof AST_Constant
25441 && self.right.is_string(compressor)) {
25442 self = make_node(AST_Binary, self, {
25443 operator: "+",
25444 left: make_node(AST_String, null, {
25445 value: "" + self.left.getValue() + self.right.left.getValue(),
25446 start: self.left.start,
25447 end: self.right.left.end
25448 }),
25449 right: self.right.right
25450 });
25451 }
25452 if (self.right instanceof AST_Constant
25453 && self.left instanceof AST_Binary
25454 && self.left.operator == "+"
25455 && self.left.right instanceof AST_Constant
25456 && self.left.is_string(compressor)) {
25457 self = make_node(AST_Binary, self, {
25458 operator: "+",
25459 left: self.left.left,
25460 right: make_node(AST_String, null, {
25461 value: "" + self.left.right.getValue() + self.right.getValue(),
25462 start: self.left.right.start,
25463 end: self.right.end
25464 })
25465 });
25466 }
25467 if (self.left instanceof AST_Binary
25468 && self.left.operator == "+"
25469 && self.left.is_string(compressor)
25470 && self.left.right instanceof AST_Constant
25471 && self.right instanceof AST_Binary
25472 && self.right.operator == "+"
25473 && self.right.left instanceof AST_Constant
25474 && self.right.is_string(compressor)) {
25475 self = make_node(AST_Binary, self, {
25476 operator: "+",
25477 left: make_node(AST_Binary, self.left, {
25478 operator: "+",
25479 left: self.left.left,
25480 right: make_node(AST_String, null, {
25481 value: "" + self.left.right.getValue() + self.right.left.getValue(),
25482 start: self.left.right.start,
25483 end: self.right.left.end
25484 })
25485 }),
25486 right: self.right.right
25487 });
25488 }
25489 }
25490 }
25491 // x && (y && z) ==> x && y && z
25492 // x || (y || z) ==> x || y || z
25493 if (self.right instanceof AST_Binary
25494 && self.right.operator == self.operator
25495 && (self.operator == "&&" || self.operator == "||"))
25496 {
25497 self.left = make_node(AST_Binary, self.left, {
25498 operator : self.operator,
25499 left : self.left,
25500 right : self.right.left
25501 });
25502 self.right = self.right.right;
25503 return self.transform(compressor);
25504 }
25505 return self.evaluate(compressor)[0];
25506 });
25507
25508 OPT(AST_SymbolRef, function(self, compressor){
25509 function isLHS(symbol, parent) {
25510 return (
25511 parent instanceof AST_Binary &&
25512 parent.operator === '=' &&
25513 parent.left === symbol
25514 );
25515 }
25516
25517 if (self.undeclared() && !isLHS(self, compressor.parent())) {
25518 var defines = compressor.option("global_defs");
25519 if (defines && defines.hasOwnProperty(self.name)) {
25520 return make_node_from_constant(compressor, defines[self.name], self);
25521 }
25522 switch (self.name) {
25523 case "undefined":
25524 return make_node(AST_Undefined, self);
25525 case "NaN":
25526 return make_node(AST_NaN, self).transform(compressor);
25527 case "Infinity":
25528 return make_node(AST_Infinity, self).transform(compressor);
25529 }
25530 }
25531 return self;
25532 });
25533
25534 OPT(AST_Infinity, function (self, compressor) {
25535 return make_node(AST_Binary, self, {
25536 operator : '/',
25537 left : make_node(AST_Number, self, {value: 1}),
25538 right : make_node(AST_Number, self, {value: 0})
25539 });
25540 });
25541
25542 OPT(AST_Undefined, function(self, compressor){
25543 if (compressor.option("unsafe")) {
25544 var scope = compressor.find_parent(AST_Scope);
25545 var undef = scope.find_variable("undefined");
25546 if (undef) {
25547 var ref = make_node(AST_SymbolRef, self, {
25548 name : "undefined",
25549 scope : scope,
25550 thedef : undef
25551 });
25552 ref.reference();
25553 return ref;
25554 }
25555 }
25556 return self;
25557 });
25558
25559 var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
25560 OPT(AST_Assign, function(self, compressor){
25561 self = self.lift_sequences(compressor);
25562 if (self.operator == "="
25563 && self.left instanceof AST_SymbolRef
25564 && self.right instanceof AST_Binary
25565 && self.right.left instanceof AST_SymbolRef
25566 && self.right.left.name == self.left.name
25567 && member(self.right.operator, ASSIGN_OPS)) {
25568 self.operator = self.right.operator + "=";
25569 self.right = self.right.right;
25570 }
25571 return self;
25572 });
25573
25574 OPT(AST_Conditional, function(self, compressor){
25575 if (!compressor.option("conditionals")) return self;
25576 if (self.condition instanceof AST_Seq) {
25577 var car = self.condition.car;
25578 self.condition = self.condition.cdr;
25579 return AST_Seq.cons(car, self);
25580 }
25581 var cond = self.condition.evaluate(compressor);
25582 if (cond.length > 1) {
25583 if (cond[1]) {
25584 compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
25585 return self.consequent;
25586 } else {
25587 compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
25588 return self.alternative;
25589 }
25590 }
25591 var negated = cond[0].negate(compressor);
25592 if (best_of(cond[0], negated) === negated) {
25593 self = make_node(AST_Conditional, self, {
25594 condition: negated,
25595 consequent: self.alternative,
25596 alternative: self.consequent
25597 });
25598 }
25599 var consequent = self.consequent;
25600 var alternative = self.alternative;
25601 if (consequent instanceof AST_Assign
25602 && alternative instanceof AST_Assign
25603 && consequent.operator == alternative.operator
25604 && consequent.left.equivalent_to(alternative.left)
25605 && !consequent.left.has_side_effects(compressor)
25606 ) {
25607 /*
25608 * Stuff like this:
25609 * if (foo) exp = something; else exp = something_else;
25610 * ==>
25611 * exp = foo ? something : something_else;
25612 */
25613 return make_node(AST_Assign, self, {
25614 operator: consequent.operator,
25615 left: consequent.left,
25616 right: make_node(AST_Conditional, self, {
25617 condition: self.condition,
25618 consequent: consequent.right,
25619 alternative: alternative.right
25620 })
25621 });
25622 }
25623 if (consequent instanceof AST_Call
25624 && alternative.TYPE === consequent.TYPE
25625 && consequent.args.length == alternative.args.length
25626 && !consequent.expression.has_side_effects(compressor)
25627 && consequent.expression.equivalent_to(alternative.expression)) {
25628 if (consequent.args.length == 0) {
25629 return make_node(AST_Seq, self, {
25630 car: self.condition,
25631 cdr: consequent
25632 });
25633 }
25634 if (consequent.args.length == 1) {
25635 consequent.args[0] = make_node(AST_Conditional, self, {
25636 condition: self.condition,
25637 consequent: consequent.args[0],
25638 alternative: alternative.args[0]
25639 });
25640 return consequent;
25641 }
25642 }
25643 // x?y?z:a:a --> x&&y?z:a
25644 if (consequent instanceof AST_Conditional
25645 && consequent.alternative.equivalent_to(alternative)) {
25646 return make_node(AST_Conditional, self, {
25647 condition: make_node(AST_Binary, self, {
25648 left: self.condition,
25649 operator: "&&",
25650 right: consequent.condition
25651 }),
25652 consequent: consequent.consequent,
25653 alternative: alternative
25654 });
25655 }
25656 // x=y?1:1 --> x=1
25657 if (consequent instanceof AST_Constant
25658 && alternative instanceof AST_Constant
25659 && consequent.equivalent_to(alternative)) {
25660 if (self.condition.has_side_effects(compressor)) {
25661 return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent.value, self)]);
25662 } else {
25663 return make_node_from_constant(compressor, consequent.value, self);
25664
25665 }
25666 }
25667 // x=y?true:false --> x=!!y
25668 if (consequent instanceof AST_True
25669 && alternative instanceof AST_False) {
25670 self.condition = self.condition.negate(compressor);
25671 return make_node(AST_UnaryPrefix, self.condition, {
25672 operator: "!",
25673 expression: self.condition
25674 });
25675 }
25676 // x=y?false:true --> x=!y
25677 if (consequent instanceof AST_False
25678 && alternative instanceof AST_True) {
25679 return self.condition.negate(compressor)
25680 }
25681 return self;
25682 });
25683
25684 OPT(AST_Boolean, function(self, compressor){
25685 if (compressor.option("booleans")) {
25686 var p = compressor.parent();
25687 if (p instanceof AST_Binary && (p.operator == "=="
25688 || p.operator == "!=")) {
25689 compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", {
25690 operator : p.operator,
25691 value : self.value,
25692 file : p.start.file,
25693 line : p.start.line,
25694 col : p.start.col,
25695 });
25696 return make_node(AST_Number, self, {
25697 value: +self.value
25698 });
25699 }
25700 return make_node(AST_UnaryPrefix, self, {
25701 operator: "!",
25702 expression: make_node(AST_Number, self, {
25703 value: 1 - self.value
25704 })
25705 });
25706 }
25707 return self;
25708 });
25709
25710 OPT(AST_Sub, function(self, compressor){
25711 var prop = self.property;
25712 if (prop instanceof AST_String && compressor.option("properties")) {
25713 prop = prop.getValue();
25714 if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) {
25715 return make_node(AST_Dot, self, {
25716 expression : self.expression,
25717 property : prop
25718 }).optimize(compressor);
25719 }
25720 var v = parseFloat(prop);
25721 if (!isNaN(v) && v.toString() == prop) {
25722 self.property = make_node(AST_Number, self.property, {
25723 value: v
25724 });
25725 }
25726 }
25727 return self;
25728 });
25729
25730 OPT(AST_Dot, function(self, compressor){
25731 var prop = self.property;
25732 if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) {
25733 return make_node(AST_Sub, self, {
25734 expression : self.expression,
25735 property : make_node(AST_String, self, {
25736 value: prop
25737 })
25738 }).optimize(compressor);
25739 }
25740 return self.evaluate(compressor)[0];
25741 });
25742
25743 function literals_in_boolean_context(self, compressor) {
25744 if (compressor.option("booleans") && compressor.in_boolean_context() && !self.has_side_effects(compressor)) {
25745 return make_node(AST_True, self);
25746 }
25747 return self;
25748 };
25749 OPT(AST_Array, literals_in_boolean_context);
25750 OPT(AST_Object, literals_in_boolean_context);
25751 OPT(AST_RegExp, literals_in_boolean_context);
25752
25753 OPT(AST_Return, function(self, compressor){
25754 if (self.value instanceof AST_Undefined) {
25755 self.value = null;
25756 }
25757 return self;
25758 });
25759
25760})();
25761
25762/***********************************************************************
25763
25764 A JavaScript tokenizer / parser / beautifier / compressor.
25765 https://github.com/mishoo/UglifyJS2
25766
25767 -------------------------------- (C) ---------------------------------
25768
25769 Author: Mihai Bazon
25770 <mihai.bazon@gmail.com>
25771 http://mihai.bazon.net/blog
25772
25773 Distributed under the BSD license:
25774
25775 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
25776
25777 Redistribution and use in source and binary forms, with or without
25778 modification, are permitted provided that the following conditions
25779 are met:
25780
25781 * Redistributions of source code must retain the above
25782 copyright notice, this list of conditions and the following
25783 disclaimer.
25784
25785 * Redistributions in binary form must reproduce the above
25786 copyright notice, this list of conditions and the following
25787 disclaimer in the documentation and/or other materials
25788 provided with the distribution.
25789
25790 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
25791 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25792 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25793 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
25794 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25795 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25796 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25797 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25798 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25799 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
25800 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25801 SUCH DAMAGE.
25802
25803 ***********************************************************************/
25804
25805"use strict";
25806
25807// a small wrapper around fitzgen's source-map library
25808function SourceMap(options) {
25809 options = defaults(options, {
25810 file : null,
25811 root : null,
25812 orig : null,
25813
25814 orig_line_diff : 0,
25815 dest_line_diff : 0,
25816 });
25817 var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
25818 var generator;
25819 if (orig_map) {
25820 generator = MOZ_SourceMap.SourceMapGenerator.fromSourceMap(orig_map);
25821 } else {
25822 generator = new MOZ_SourceMap.SourceMapGenerator({
25823 file : options.file,
25824 sourceRoot : options.root
25825 });
25826 }
25827 function add(source, gen_line, gen_col, orig_line, orig_col, name) {
25828 if (orig_map) {
25829 var info = orig_map.originalPositionFor({
25830 line: orig_line,
25831 column: orig_col
25832 });
25833 if (info.source === null) {
25834 return;
25835 }
25836 source = info.source;
25837 orig_line = info.line;
25838 orig_col = info.column;
25839 name = info.name || name;
25840 }
25841 generator.addMapping({
25842 generated : { line: gen_line + options.dest_line_diff, column: gen_col },
25843 original : { line: orig_line + options.orig_line_diff, column: orig_col },
25844 source : source,
25845 name : name
25846 });
25847 }
25848 return {
25849 add : add,
25850 get : function() { return generator },
25851 toString : function() { return JSON.stringify(generator.toJSON()); }
25852 };
25853};
25854
25855/***********************************************************************
25856
25857 A JavaScript tokenizer / parser / beautifier / compressor.
25858 https://github.com/mishoo/UglifyJS2
25859
25860 -------------------------------- (C) ---------------------------------
25861
25862 Author: Mihai Bazon
25863 <mihai.bazon@gmail.com>
25864 http://mihai.bazon.net/blog
25865
25866 Distributed under the BSD license:
25867
25868 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
25869
25870 Redistribution and use in source and binary forms, with or without
25871 modification, are permitted provided that the following conditions
25872 are met:
25873
25874 * Redistributions of source code must retain the above
25875 copyright notice, this list of conditions and the following
25876 disclaimer.
25877
25878 * Redistributions in binary form must reproduce the above
25879 copyright notice, this list of conditions and the following
25880 disclaimer in the documentation and/or other materials
25881 provided with the distribution.
25882
25883 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
25884 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25885 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25886 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
25887 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25888 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25889 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25890 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25891 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25892 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
25893 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25894 SUCH DAMAGE.
25895
25896 ***********************************************************************/
25897
25898"use strict";
25899
25900(function(){
25901
25902 var MOZ_TO_ME = {
25903 ExpressionStatement: function(M) {
25904 var expr = M.expression;
25905 if (expr.type === "Literal" && typeof expr.value === "string") {
25906 return new AST_Directive({
25907 start: my_start_token(M),
25908 end: my_end_token(M),
25909 value: expr.value
25910 });
25911 }
25912 return new AST_SimpleStatement({
25913 start: my_start_token(M),
25914 end: my_end_token(M),
25915 body: from_moz(expr)
25916 });
25917 },
25918 TryStatement: function(M) {
25919 var handlers = M.handlers || [M.handler];
25920 if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) {
25921 throw new Error("Multiple catch clauses are not supported.");
25922 }
25923 return new AST_Try({
25924 start : my_start_token(M),
25925 end : my_end_token(M),
25926 body : from_moz(M.block).body,
25927 bcatch : from_moz(handlers[0]),
25928 bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
25929 });
25930 },
25931 Property: function(M) {
25932 var key = M.key;
25933 var name = key.type == "Identifier" ? key.name : key.value;
25934 var args = {
25935 start : my_start_token(key),
25936 end : my_end_token(M.value),
25937 key : name,
25938 value : from_moz(M.value)
25939 };
25940 switch (M.kind) {
25941 case "init":
25942 return new AST_ObjectKeyVal(args);
25943 case "set":
25944 args.value.name = from_moz(key);
25945 return new AST_ObjectSetter(args);
25946 case "get":
25947 args.value.name = from_moz(key);
25948 return new AST_ObjectGetter(args);
25949 }
25950 },
25951 ObjectExpression: function(M) {
25952 return new AST_Object({
25953 start : my_start_token(M),
25954 end : my_end_token(M),
25955 properties : M.properties.map(function(prop){
25956 prop.type = "Property";
25957 return from_moz(prop)
25958 })
25959 });
25960 },
25961 SequenceExpression: function(M) {
25962 return AST_Seq.from_array(M.expressions.map(from_moz));
25963 },
25964 MemberExpression: function(M) {
25965 return new (M.computed ? AST_Sub : AST_Dot)({
25966 start : my_start_token(M),
25967 end : my_end_token(M),
25968 property : M.computed ? from_moz(M.property) : M.property.name,
25969 expression : from_moz(M.object)
25970 });
25971 },
25972 SwitchCase: function(M) {
25973 return new (M.test ? AST_Case : AST_Default)({
25974 start : my_start_token(M),
25975 end : my_end_token(M),
25976 expression : from_moz(M.test),
25977 body : M.consequent.map(from_moz)
25978 });
25979 },
25980 VariableDeclaration: function(M) {
25981 return new (M.kind === "const" ? AST_Const : AST_Var)({
25982 start : my_start_token(M),
25983 end : my_end_token(M),
25984 definitions : M.declarations.map(from_moz)
25985 });
25986 },
25987 Literal: function(M) {
25988 var val = M.value, args = {
25989 start : my_start_token(M),
25990 end : my_end_token(M)
25991 };
25992 if (val === null) return new AST_Null(args);
25993 switch (typeof val) {
25994 case "string":
25995 args.value = val;
25996 return new AST_String(args);
25997 case "number":
25998 args.value = val;
25999 return new AST_Number(args);
26000 case "boolean":
26001 return new (val ? AST_True : AST_False)(args);
26002 default:
26003 var rx = M.regex;
26004 if (rx && rx.pattern) {
26005 // RegExpLiteral as per ESTree AST spec
26006 args.value = new RegExp(rx.pattern, rx.flags).toString();
26007 } else {
26008 // support legacy RegExp
26009 args.value = M.regex && M.raw ? M.raw : val;
26010 }
26011 return new AST_RegExp(args);
26012 }
26013 },
26014 Identifier: function(M) {
26015 var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
26016 return new ( p.type == "LabeledStatement" ? AST_Label
26017 : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
26018 : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
26019 : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
26020 : p.type == "CatchClause" ? AST_SymbolCatch
26021 : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
26022 : AST_SymbolRef)({
26023 start : my_start_token(M),
26024 end : my_end_token(M),
26025 name : M.name
26026 });
26027 }
26028 };
26029
26030 MOZ_TO_ME.UpdateExpression =
26031 MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) {
26032 var prefix = "prefix" in M ? M.prefix
26033 : M.type == "UnaryExpression" ? true : false;
26034 return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
26035 start : my_start_token(M),
26036 end : my_end_token(M),
26037 operator : M.operator,
26038 expression : from_moz(M.argument)
26039 });
26040 };
26041
26042 map("Program", AST_Toplevel, "body@body");
26043 map("EmptyStatement", AST_EmptyStatement);
26044 map("BlockStatement", AST_BlockStatement, "body@body");
26045 map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
26046 map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
26047 map("BreakStatement", AST_Break, "label>label");
26048 map("ContinueStatement", AST_Continue, "label>label");
26049 map("WithStatement", AST_With, "object>expression, body>body");
26050 map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
26051 map("ReturnStatement", AST_Return, "argument>value");
26052 map("ThrowStatement", AST_Throw, "argument>value");
26053 map("WhileStatement", AST_While, "test>condition, body>body");
26054 map("DoWhileStatement", AST_Do, "test>condition, body>body");
26055 map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
26056 map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
26057 map("DebuggerStatement", AST_Debugger);
26058 map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
26059 map("VariableDeclarator", AST_VarDef, "id>name, init>value");
26060 map("CatchClause", AST_Catch, "param>argname, body%body");
26061
26062 map("ThisExpression", AST_This);
26063 map("ArrayExpression", AST_Array, "elements@elements");
26064 map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
26065 map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
26066 map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
26067 map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
26068 map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
26069 map("NewExpression", AST_New, "callee>expression, arguments@args");
26070 map("CallExpression", AST_Call, "callee>expression, arguments@args");
26071
26072 def_to_moz(AST_Directive, function To_Moz_Directive(M) {
26073 return {
26074 type: "ExpressionStatement",
26075 expression: {
26076 type: "Literal",
26077 value: M.value
26078 }
26079 };
26080 });
26081
26082 def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) {
26083 return {
26084 type: "ExpressionStatement",
26085 expression: to_moz(M.body)
26086 };
26087 });
26088
26089 def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) {
26090 return {
26091 type: "SwitchCase",
26092 test: to_moz(M.expression),
26093 consequent: M.body.map(to_moz)
26094 };
26095 });
26096
26097 def_to_moz(AST_Try, function To_Moz_TryStatement(M) {
26098 return {
26099 type: "TryStatement",
26100 block: to_moz_block(M),
26101 handler: to_moz(M.bcatch),
26102 guardedHandlers: [],
26103 finalizer: to_moz(M.bfinally)
26104 };
26105 });
26106
26107 def_to_moz(AST_Catch, function To_Moz_CatchClause(M) {
26108 return {
26109 type: "CatchClause",
26110 param: to_moz(M.argname),
26111 guard: null,
26112 body: to_moz_block(M)
26113 };
26114 });
26115
26116 def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
26117 return {
26118 type: "VariableDeclaration",
26119 kind: M instanceof AST_Const ? "const" : "var",
26120 declarations: M.definitions.map(to_moz)
26121 };
26122 });
26123
26124 def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) {
26125 return {
26126 type: "SequenceExpression",
26127 expressions: M.to_array().map(to_moz)
26128 };
26129 });
26130
26131 def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
26132 var isComputed = M instanceof AST_Sub;
26133 return {
26134 type: "MemberExpression",
26135 object: to_moz(M.expression),
26136 computed: isComputed,
26137 property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property}
26138 };
26139 });
26140
26141 def_to_moz(AST_Unary, function To_Moz_Unary(M) {
26142 return {
26143 type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression",
26144 operator: M.operator,
26145 prefix: M instanceof AST_UnaryPrefix,
26146 argument: to_moz(M.expression)
26147 };
26148 });
26149
26150 def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) {
26151 return {
26152 type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression",
26153 left: to_moz(M.left),
26154 operator: M.operator,
26155 right: to_moz(M.right)
26156 };
26157 });
26158
26159 def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
26160 return {
26161 type: "ObjectExpression",
26162 properties: M.properties.map(to_moz)
26163 };
26164 });
26165
26166 def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
26167 var key = (
26168 is_identifier(M.key)
26169 ? {type: "Identifier", name: M.key}
26170 : {type: "Literal", value: M.key}
26171 );
26172 var kind;
26173 if (M instanceof AST_ObjectKeyVal) {
26174 kind = "init";
26175 } else
26176 if (M instanceof AST_ObjectGetter) {
26177 kind = "get";
26178 } else
26179 if (M instanceof AST_ObjectSetter) {
26180 kind = "set";
26181 }
26182 return {
26183 type: "Property",
26184 kind: kind,
26185 key: key,
26186 value: to_moz(M.value)
26187 };
26188 });
26189
26190 def_to_moz(AST_Symbol, function To_Moz_Identifier(M) {
26191 var def = M.definition();
26192 return {
26193 type: "Identifier",
26194 name: def ? def.mangled_name || def.name : M.name
26195 };
26196 });
26197
26198 def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
26199 var value = M.value;
26200 return {
26201 type: "Literal",
26202 value: value,
26203 raw: value.toString(),
26204 regex: {
26205 pattern: value.source,
26206 flags: value.toString().match(/[gimuy]*$/)[0]
26207 }
26208 };
26209 });
26210
26211 def_to_moz(AST_Constant, function To_Moz_Literal(M) {
26212 var value = M.value;
26213 if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
26214 return {
26215 type: "UnaryExpression",
26216 operator: "-",
26217 prefix: true,
26218 argument: {
26219 type: "Literal",
26220 value: -value,
26221 raw: M.start.raw
26222 }
26223 };
26224 }
26225 return {
26226 type: "Literal",
26227 value: value,
26228 raw: M.start.raw
26229 };
26230 });
26231
26232 def_to_moz(AST_Atom, function To_Moz_Atom(M) {
26233 return {
26234 type: "Identifier",
26235 name: String(M.value)
26236 };
26237 });
26238
26239 AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
26240 AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
26241 AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null });
26242
26243 AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast);
26244 AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast);
26245
26246 /* -----[ tools ]----- */
26247
26248 function raw_token(moznode) {
26249 if (moznode.type == "Literal") {
26250 return moznode.raw != null ? moznode.raw : moznode.value + "";
26251 }
26252 }
26253
26254 function my_start_token(moznode) {
26255 var loc = moznode.loc, start = loc && loc.start;
26256 var range = moznode.range;
26257 return new AST_Token({
26258 file : loc && loc.source,
26259 line : start && start.line,
26260 col : start && start.column,
26261 pos : range ? range[0] : moznode.start,
26262 endline : start && start.line,
26263 endcol : start && start.column,
26264 endpos : range ? range[0] : moznode.start,
26265 raw : raw_token(moznode),
26266 });
26267 };
26268
26269 function my_end_token(moznode) {
26270 var loc = moznode.loc, end = loc && loc.end;
26271 var range = moznode.range;
26272 return new AST_Token({
26273 file : loc && loc.source,
26274 line : end && end.line,
26275 col : end && end.column,
26276 pos : range ? range[1] : moznode.end,
26277 endline : end && end.line,
26278 endcol : end && end.column,
26279 endpos : range ? range[1] : moznode.end,
26280 raw : raw_token(moznode),
26281 });
26282 };
26283
26284 function map(moztype, mytype, propmap) {
26285 var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
26286 moz_to_me += "return new U2." + mytype.name + "({\n" +
26287 "start: my_start_token(M),\n" +
26288 "end: my_end_token(M)";
26289
26290 var me_to_moz = "function To_Moz_" + moztype + "(M){\n";
26291 me_to_moz += "return {\n" +
26292 "type: " + JSON.stringify(moztype);
26293
26294 if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
26295 var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
26296 if (!m) throw new Error("Can't understand property map: " + prop);
26297 var moz = m[1], how = m[2], my = m[3];
26298 moz_to_me += ",\n" + my + ": ";
26299 me_to_moz += ",\n" + moz + ": ";
26300 switch (how) {
26301 case "@":
26302 moz_to_me += "M." + moz + ".map(from_moz)";
26303 me_to_moz += "M." + my + ".map(to_moz)";
26304 break;
26305 case ">":
26306 moz_to_me += "from_moz(M." + moz + ")";
26307 me_to_moz += "to_moz(M." + my + ")";
26308 break;
26309 case "=":
26310 moz_to_me += "M." + moz;
26311 me_to_moz += "M." + my;
26312 break;
26313 case "%":
26314 moz_to_me += "from_moz(M." + moz + ").body";
26315 me_to_moz += "to_moz_block(M)";
26316 break;
26317 default:
26318 throw new Error("Can't understand operator in propmap: " + prop);
26319 }
26320 });
26321
26322 moz_to_me += "\n})\n}";
26323 me_to_moz += "\n}\n}";
26324
26325 //moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
26326 //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true });
26327 //console.log(moz_to_me);
26328
26329 moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
26330 exports, my_start_token, my_end_token, from_moz
26331 );
26332 me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
26333 to_moz, to_moz_block
26334 );
26335 MOZ_TO_ME[moztype] = moz_to_me;
26336 def_to_moz(mytype, me_to_moz);
26337 };
26338
26339 var FROM_MOZ_STACK = null;
26340
26341 function from_moz(node) {
26342 FROM_MOZ_STACK.push(node);
26343 var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
26344 FROM_MOZ_STACK.pop();
26345 return ret;
26346 };
26347
26348 AST_Node.from_mozilla_ast = function(node){
26349 var save_stack = FROM_MOZ_STACK;
26350 FROM_MOZ_STACK = [];
26351 var ast = from_moz(node);
26352 FROM_MOZ_STACK = save_stack;
26353 return ast;
26354 };
26355
26356 function set_moz_loc(mynode, moznode, myparent) {
26357 var start = mynode.start;
26358 var end = mynode.end;
26359 if (start.pos != null && end.endpos != null) {
26360 moznode.range = [start.pos, end.endpos];
26361 }
26362 if (start.line) {
26363 moznode.loc = {
26364 start: {line: start.line, column: start.col},
26365 end: end.endline ? {line: end.endline, column: end.endcol} : null
26366 };
26367 if (start.file) {
26368 moznode.loc.source = start.file;
26369 }
26370 }
26371 return moznode;
26372 };
26373
26374 function def_to_moz(mytype, handler) {
26375 mytype.DEFMETHOD("to_mozilla_ast", function() {
26376 return set_moz_loc(this, handler(this));
26377 });
26378 };
26379
26380 function to_moz(node) {
26381 return node != null ? node.to_mozilla_ast() : null;
26382 };
26383
26384 function to_moz_block(node) {
26385 return {
26386 type: "BlockStatement",
26387 body: node.body.map(to_moz)
26388 };
26389 };
26390
26391})();
26392
26393/***********************************************************************
26394
26395 A JavaScript tokenizer / parser / beautifier / compressor.
26396 https://github.com/mishoo/UglifyJS2
26397
26398 -------------------------------- (C) ---------------------------------
26399
26400 Author: Mihai Bazon
26401 <mihai.bazon@gmail.com>
26402 http://mihai.bazon.net/blog
26403
26404 Distributed under the BSD license:
26405
26406 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
26407
26408 Redistribution and use in source and binary forms, with or without
26409 modification, are permitted provided that the following conditions
26410 are met:
26411
26412 * Redistributions of source code must retain the above
26413 copyright notice, this list of conditions and the following
26414 disclaimer.
26415
26416 * Redistributions in binary form must reproduce the above
26417 copyright notice, this list of conditions and the following
26418 disclaimer in the documentation and/or other materials
26419 provided with the distribution.
26420
26421 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
26422 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26423 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26424 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
26425 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26426 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26427 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26428 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26429 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26430 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26431 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26432 SUCH DAMAGE.
26433
26434 ***********************************************************************/
26435
26436"use strict";
26437
26438function find_builtins() {
26439 var a = [];
26440 [ Object, Array, Function, Number,
26441 String, Boolean, Error, Math,
26442 Date, RegExp
26443 ].forEach(function(ctor){
26444 Object.getOwnPropertyNames(ctor).map(add);
26445 if (ctor.prototype) {
26446 Object.getOwnPropertyNames(ctor.prototype).map(add);
26447 }
26448 });
26449 function add(name) {
26450 push_uniq(a, name);
26451 }
26452 return a;
26453}
26454
26455function mangle_properties(ast, options) {
26456 options = defaults(options, {
26457 reserved : null,
26458 cache : null,
26459 only_cache : false,
26460 regex : null
26461 });
26462
26463 var reserved = options.reserved;
26464 if (reserved == null)
26465 reserved = find_builtins();
26466
26467 var cache = options.cache;
26468 if (cache == null) {
26469 cache = {
26470 cname: -1,
26471 props: new Dictionary()
26472 };
26473 }
26474
26475 var regex = options.regex;
26476
26477 var names_to_mangle = [];
26478 var unmangleable = [];
26479
26480 // step 1: find candidates to mangle
26481 ast.walk(new TreeWalker(function(node){
26482 if (node instanceof AST_ObjectKeyVal) {
26483 add(node.key);
26484 }
26485 else if (node instanceof AST_ObjectProperty) {
26486 // setter or getter, since KeyVal is handled above
26487 add(node.key.name);
26488 }
26489 else if (node instanceof AST_Dot) {
26490 if (this.parent() instanceof AST_Assign) {
26491 add(node.property);
26492 }
26493 }
26494 else if (node instanceof AST_Sub) {
26495 if (this.parent() instanceof AST_Assign) {
26496 addStrings(node.property);
26497 }
26498 }
26499 }));
26500
26501 // step 2: transform the tree, renaming properties
26502 return ast.transform(new TreeTransformer(function(node){
26503 if (node instanceof AST_ObjectKeyVal) {
26504 node.key = mangle(node.key);
26505 }
26506 else if (node instanceof AST_ObjectProperty) {
26507 // setter or getter
26508 node.key.name = mangle(node.key.name);
26509 }
26510 else if (node instanceof AST_Dot) {
26511 node.property = mangle(node.property);
26512 }
26513 else if (node instanceof AST_Sub) {
26514 node.property = mangleStrings(node.property);
26515 }
26516 // else if (node instanceof AST_String) {
26517 // if (should_mangle(node.value)) {
26518 // AST_Node.warn(
26519 // "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
26520 // file : node.start.file,
26521 // line : node.start.line,
26522 // col : node.start.col,
26523 // prop : node.value
26524 // }
26525 // );
26526 // }
26527 // }
26528 }));
26529
26530 // only function declarations after this line
26531
26532 function can_mangle(name) {
26533 if (unmangleable.indexOf(name) >= 0) return false;
26534 if (reserved.indexOf(name) >= 0) return false;
26535 if (options.only_cache) {
26536 return cache.props.has(name);
26537 }
26538 if (/^[0-9.]+$/.test(name)) return false;
26539 return true;
26540 }
26541
26542 function should_mangle(name) {
26543 if (regex && !regex.test(name)) return false;
26544 if (reserved.indexOf(name) >= 0) return false;
26545 return cache.props.has(name)
26546 || names_to_mangle.indexOf(name) >= 0;
26547 }
26548
26549 function add(name) {
26550 if (can_mangle(name))
26551 push_uniq(names_to_mangle, name);
26552
26553 if (!should_mangle(name)) {
26554 push_uniq(unmangleable, name);
26555 }
26556 }
26557
26558 function mangle(name) {
26559 if (!should_mangle(name)) {
26560 return name;
26561 }
26562
26563 var mangled = cache.props.get(name);
26564 if (!mangled) {
26565 do {
26566 mangled = base54(++cache.cname);
26567 } while (!can_mangle(mangled));
26568 cache.props.set(name, mangled);
26569 }
26570 return mangled;
26571 }
26572
26573 function addStrings(node) {
26574 var out = {};
26575 try {
26576 (function walk(node){
26577 node.walk(new TreeWalker(function(node){
26578 if (node instanceof AST_Seq) {
26579 walk(node.cdr);
26580 return true;
26581 }
26582 if (node instanceof AST_String) {
26583 add(node.value);
26584 return true;
26585 }
26586 if (node instanceof AST_Conditional) {
26587 walk(node.consequent);
26588 walk(node.alternative);
26589 return true;
26590 }
26591 throw out;
26592 }));
26593 })(node);
26594 } catch(ex) {
26595 if (ex !== out) throw ex;
26596 }
26597 }
26598
26599 function mangleStrings(node) {
26600 return node.transform(new TreeTransformer(function(node){
26601 if (node instanceof AST_Seq) {
26602 node.cdr = mangleStrings(node.cdr);
26603 }
26604 else if (node instanceof AST_String) {
26605 node.value = mangle(node.value);
26606 }
26607 else if (node instanceof AST_Conditional) {
26608 node.consequent = mangleStrings(node.consequent);
26609 node.alternative = mangleStrings(node.alternative);
26610 }
26611 return node;
26612 }));
26613 }
26614
26615}
26616
26617AST_Node.warn_function = function(txt) { logger.error("uglifyjs2 WARN: " + txt); };
26618exports.minify = function(files, options, name) {
26619 options = defaults(options, {
26620 spidermonkey : false,
26621 outSourceMap : null,
26622 sourceRoot : null,
26623 inSourceMap : null,
26624 fromString : false,
26625 warnings : false,
26626 mangle : {},
26627 output : null,
26628 compress : {}
26629 });
26630 base54.reset();
26631
26632 // 1. parse
26633 var toplevel = null,
26634 sourcesContent = {};
26635
26636 if (options.spidermonkey) {
26637 toplevel = AST_Node.from_mozilla_ast(files);
26638 } else {
26639 if (typeof files == "string")
26640 files = [ files ];
26641 files.forEach(function(file, i){
26642 var code = options.fromString
26643 ? file
26644 : rjsFile.readFile(file, "utf8");
26645 sourcesContent[file] = code;
26646 toplevel = parse(code, {
26647 filename: options.fromString ? name : file,
26648 toplevel: toplevel
26649 });
26650 });
26651 }
26652 if (options.wrap) {
26653 toplevel = toplevel.wrap_commonjs(options.wrap, options.exportAll);
26654 }
26655
26656 // 2. compress
26657 if (options.compress) {
26658 var compress = { warnings: options.warnings };
26659 merge(compress, options.compress);
26660 toplevel.figure_out_scope();
26661 var sq = Compressor(compress);
26662 toplevel = toplevel.transform(sq);
26663 }
26664
26665 // 3. mangle
26666 if (options.mangle) {
26667 toplevel.figure_out_scope(options.mangle);
26668 toplevel.compute_char_frequency(options.mangle);
26669 toplevel.mangle_names(options.mangle);
26670 }
26671
26672 // 4. output
26673 var inMap = options.inSourceMap;
26674 var output = {};
26675 if (typeof options.inSourceMap == "string") {
26676 inMap = rjsFile.readFile(options.inSourceMap, "utf8");
26677 }
26678 if (options.outSourceMap) {
26679 output.source_map = SourceMap({
26680 file: options.outSourceMap,
26681 orig: inMap,
26682 root: options.sourceRoot
26683 });
26684 if (options.sourceMapIncludeSources) {
26685 for (var file in sourcesContent) {
26686 if (sourcesContent.hasOwnProperty(file)) {
26687 output.source_map.get().setSourceContent(file, sourcesContent[file]);
26688 }
26689 }
26690 }
26691
26692 }
26693 if (options.output) {
26694 merge(output, options.output);
26695 }
26696 var stream = OutputStream(output);
26697 toplevel.print(stream);
26698
26699 if (options.outSourceMap && "string" === typeof options.outSourceMap) {
26700 stream += "\n//# sourceMappingURL=" + options.outSourceMap;
26701 }
26702
26703 var source_map = output.source_map;
26704 if (source_map) {
26705 source_map = source_map + "";
26706 }
26707
26708 return {
26709 code : stream + "",
26710 map : source_map
26711 };
26712};
26713
26714// exports.describe_ast = function() {
26715// function doitem(ctor) {
26716// var sub = {};
26717// ctor.SUBCLASSES.forEach(function(ctor){
26718// sub[ctor.TYPE] = doitem(ctor);
26719// });
26720// var ret = {};
26721// if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS;
26722// if (ctor.SUBCLASSES.length > 0) ret.sub = sub;
26723// return ret;
26724// }
26725// return doitem(AST_Node).sub;
26726// }
26727
26728exports.describe_ast = function() {
26729 var out = OutputStream({ beautify: true });
26730 function doitem(ctor) {
26731 out.print("AST_" + ctor.TYPE);
26732 var props = ctor.SELF_PROPS.filter(function(prop){
26733 return !/^\$/.test(prop);
26734 });
26735 if (props.length > 0) {
26736 out.space();
26737 out.with_parens(function(){
26738 props.forEach(function(prop, i){
26739 if (i) out.space();
26740 out.print(prop);
26741 });
26742 });
26743 }
26744 if (ctor.documentation) {
26745 out.space();
26746 out.print_string(ctor.documentation);
26747 }
26748 if (ctor.SUBCLASSES.length > 0) {
26749 out.space();
26750 out.with_block(function(){
26751 ctor.SUBCLASSES.forEach(function(ctor, i){
26752 out.indent();
26753 doitem(ctor);
26754 out.newline();
26755 });
26756 });
26757 }
26758 };
26759 doitem(AST_Node);
26760 return out + "";
26761};
26762
26763});
26764/**
26765 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
26766 * Available via the MIT or new BSD license.
26767 * see: http://github.com/jrburke/requirejs for details
26768 */
26769
26770/*jslint plusplus: true */
26771/*global define: false */
26772
26773define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) {
26774 'use strict';
26775
26776 function arrayToString(ary) {
26777 var output = '[';
26778 if (ary) {
26779 ary.forEach(function (item, i) {
26780 output += (i > 0 ? ',' : '') + '"' + lang.jsEscape(item) + '"';
26781 });
26782 }
26783 output += ']';
26784
26785 return output;
26786 }
26787
26788 //This string is saved off because JSLint complains
26789 //about obj.arguments use, as 'reserved word'
26790 var argPropName = 'arguments',
26791 //Default object to use for "scope" checking for UMD identifiers.
26792 emptyScope = {},
26793 mixin = lang.mixin,
26794 hasProp = lang.hasProp;
26795
26796 //From an esprima example for traversing its ast.
26797 function traverse(object, visitor) {
26798 var key, child;
26799
26800 if (!object) {
26801 return;
26802 }
26803
26804 if (visitor.call(null, object) === false) {
26805 return false;
26806 }
26807 for (key in object) {
26808 if (object.hasOwnProperty(key)) {
26809 child = object[key];
26810 if (typeof child === 'object' && child !== null) {
26811 if (traverse(child, visitor) === false) {
26812 return false;
26813 }
26814 }
26815 }
26816 }
26817 }
26818
26819 //Like traverse, but visitor returning false just
26820 //stops that subtree analysis, not the rest of tree
26821 //visiting.
26822 function traverseBroad(object, visitor) {
26823 var key, child;
26824
26825 if (!object) {
26826 return;
26827 }
26828
26829 if (visitor.call(null, object) === false) {
26830 return false;
26831 }
26832 for (key in object) {
26833 if (object.hasOwnProperty(key)) {
26834 child = object[key];
26835 if (typeof child === 'object' && child !== null) {
26836 traverseBroad(child, visitor);
26837 }
26838 }
26839 }
26840 }
26841
26842 /**
26843 * Pulls out dependencies from an array literal with just string members.
26844 * If string literals, will just return those string values in an array,
26845 * skipping other items in the array.
26846 *
26847 * @param {Node} node an AST node.
26848 *
26849 * @returns {Array} an array of strings.
26850 * If null is returned, then it means the input node was not a valid
26851 * dependency.
26852 */
26853 function getValidDeps(node) {
26854 if (!node || node.type !== 'ArrayExpression' || !node.elements) {
26855 return;
26856 }
26857
26858 var deps = [];
26859
26860 node.elements.some(function (elem) {
26861 if (elem.type === 'Literal') {
26862 deps.push(elem.value);
26863 }
26864 });
26865
26866 return deps.length ? deps : undefined;
26867 }
26868
26869 // Detects regular or arrow function expressions as the desired expression
26870 // type.
26871 function isFnExpression(node) {
26872 return (node && (node.type === 'FunctionExpression' ||
26873 node.type === 'ArrowFunctionExpression'));
26874 }
26875
26876 /**
26877 * Main parse function. Returns a string of any valid require or
26878 * define/require.def calls as part of one JavaScript source string.
26879 * @param {String} moduleName the module name that represents this file.
26880 * It is used to create a default define if there is not one already for the
26881 * file. This allows properly tracing dependencies for builds. Otherwise, if
26882 * the file just has a require() call, the file dependencies will not be
26883 * properly reflected: the file will come before its dependencies.
26884 * @param {String} moduleName
26885 * @param {String} fileName
26886 * @param {String} fileContents
26887 * @param {Object} options optional options. insertNeedsDefine: true will
26888 * add calls to require.needsDefine() if appropriate.
26889 * @returns {String} JS source string or null, if no require or
26890 * define/require.def calls are found.
26891 */
26892 function parse(moduleName, fileName, fileContents, options) {
26893 options = options || {};
26894
26895 //Set up source input
26896 var i, moduleCall, depString,
26897 moduleDeps = [],
26898 result = '',
26899 moduleList = [],
26900 needsDefine = true,
26901 astRoot = esprima.parse(fileContents);
26902
26903 parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier, fnExpScope) {
26904 if (!deps) {
26905 deps = [];
26906 }
26907
26908 if (callName === 'define' && (!name || name === moduleName)) {
26909 needsDefine = false;
26910 }
26911
26912 if (!name) {
26913 //If there is no module name, the dependencies are for
26914 //this file/default module name.
26915 moduleDeps = moduleDeps.concat(deps);
26916 } else {
26917 moduleList.push({
26918 name: name,
26919 deps: deps
26920 });
26921 }
26922
26923 if (callName === 'define' && factoryIdentifier && hasProp(fnExpScope, factoryIdentifier)) {
26924 return factoryIdentifier;
26925 }
26926
26927 //If define was found, no need to dive deeper, unless
26928 //the config explicitly wants to dig deeper.
26929 return !!options.findNestedDependencies;
26930 }, options);
26931
26932 if (options.insertNeedsDefine && needsDefine) {
26933 result += 'require.needsDefine("' + moduleName + '");';
26934 }
26935
26936 if (moduleDeps.length || moduleList.length) {
26937 for (i = 0; i < moduleList.length; i++) {
26938 moduleCall = moduleList[i];
26939 if (result) {
26940 result += '\n';
26941 }
26942
26943 //If this is the main module for this file, combine any
26944 //"anonymous" dependencies (could come from a nested require
26945 //call) with this module.
26946 if (moduleCall.name === moduleName) {
26947 moduleCall.deps = moduleCall.deps.concat(moduleDeps);
26948 moduleDeps = [];
26949 }
26950
26951 depString = arrayToString(moduleCall.deps);
26952 result += 'define("' + moduleCall.name + '",' +
26953 depString + ');';
26954 }
26955 if (moduleDeps.length) {
26956 if (result) {
26957 result += '\n';
26958 }
26959 depString = arrayToString(moduleDeps);
26960 result += 'define("' + moduleName + '",' + depString + ');';
26961 }
26962 }
26963
26964 return result || null;
26965 }
26966
26967 parse.traverse = traverse;
26968 parse.traverseBroad = traverseBroad;
26969 parse.isFnExpression = isFnExpression;
26970
26971 /**
26972 * Handles parsing a file recursively for require calls.
26973 * @param {Array} parentNode the AST node to start with.
26974 * @param {Function} onMatch function to call on a parse match.
26975 * @param {Object} [options] This is normally the build config options if
26976 * it is passed.
26977 * @param {Object} [fnExpScope] holds list of function expresssion
26978 * argument identifiers, set up internally, not passed in
26979 */
26980 parse.recurse = function (object, onMatch, options, fnExpScope) {
26981 //Like traverse, but skips if branches that would not be processed
26982 //after has application that results in tests of true or false boolean
26983 //literal values.
26984 var key, child, result, i, params, param, tempObject,
26985 hasHas = options && options.has;
26986
26987 fnExpScope = fnExpScope || emptyScope;
26988
26989 if (!object) {
26990 return;
26991 }
26992
26993 //If has replacement has resulted in if(true){} or if(false){}, take
26994 //the appropriate branch and skip the other one.
26995 if (hasHas && object.type === 'IfStatement' && object.test.type &&
26996 object.test.type === 'Literal') {
26997 if (object.test.value) {
26998 //Take the if branch
26999 this.recurse(object.consequent, onMatch, options, fnExpScope);
27000 } else {
27001 //Take the else branch
27002 this.recurse(object.alternate, onMatch, options, fnExpScope);
27003 }
27004 } else {
27005 result = this.parseNode(object, onMatch, fnExpScope);
27006 if (result === false) {
27007 return;
27008 } else if (typeof result === 'string') {
27009 return result;
27010 }
27011
27012 //Build up a "scope" object that informs nested recurse calls if
27013 //the define call references an identifier that is likely a UMD
27014 //wrapped function expression argument.
27015 //Catch (function(a) {... wrappers
27016 if (object.type === 'ExpressionStatement' && object.expression &&
27017 object.expression.type === 'CallExpression' && object.expression.callee &&
27018 isFnExpression(object.expression.callee)) {
27019 tempObject = object.expression.callee;
27020 }
27021 // Catch !function(a) {... wrappers
27022 if (object.type === 'UnaryExpression' && object.argument &&
27023 object.argument.type === 'CallExpression' && object.argument.callee &&
27024 isFnExpression(object.argument.callee)) {
27025 tempObject = object.argument.callee;
27026 }
27027 if (tempObject && tempObject.params && tempObject.params.length) {
27028 params = tempObject.params;
27029 fnExpScope = mixin({}, fnExpScope, true);
27030 for (i = 0; i < params.length; i++) {
27031 param = params[i];
27032 if (param.type === 'Identifier') {
27033 fnExpScope[param.name] = true;
27034 }
27035 }
27036 }
27037
27038 for (key in object) {
27039 if (object.hasOwnProperty(key)) {
27040 child = object[key];
27041 if (typeof child === 'object' && child !== null) {
27042 result = this.recurse(child, onMatch, options, fnExpScope);
27043 if (typeof result === 'string') {
27044 break;
27045 }
27046 }
27047 }
27048 }
27049
27050 //Check for an identifier for a factory function identifier being
27051 //passed in as a function expression, indicating a UMD-type of
27052 //wrapping.
27053 if (typeof result === 'string') {
27054 if (hasProp(fnExpScope, result)) {
27055 //result still in scope, keep jumping out indicating the
27056 //identifier still in use.
27057 return result;
27058 }
27059
27060 return;
27061 }
27062 }
27063 };
27064
27065 /**
27066 * Determines if the file defines the require/define module API.
27067 * Specifically, it looks for the `define.amd = ` expression.
27068 * @param {String} fileName
27069 * @param {String} fileContents
27070 * @returns {Boolean}
27071 */
27072 parse.definesRequire = function (fileName, fileContents) {
27073 var foundDefine = false,
27074 foundDefineAmd = false;
27075
27076 traverse(esprima.parse(fileContents), function (node) {
27077 // Look for a top level declaration of a define, like
27078 // var requirejs, require, define, off Program body.
27079 if (node.type === 'Program' && node.body && node.body.length) {
27080 foundDefine = node.body.some(function(bodyNode) {
27081 // var define
27082 if (bodyNode.type === 'VariableDeclaration') {
27083 var decls = bodyNode.declarations;
27084 if (decls) {
27085 var hasVarDefine = decls.some(function(declNode) {
27086 return (declNode.type === 'VariableDeclarator' &&
27087 declNode.id &&
27088 declNode.id.type === 'Identifier' &&
27089 declNode.id.name === 'define');
27090 });
27091 if (hasVarDefine) {
27092 return true;
27093 }
27094 }
27095 }
27096
27097 // function define() {}
27098 if (bodyNode.type === 'FunctionDeclaration' &&
27099 bodyNode.id &&
27100 bodyNode.id.type === 'Identifier' &&
27101 bodyNode.id.name === 'define') {
27102 return true;
27103 }
27104
27105
27106
27107
27108
27109
27110 });
27111 }
27112
27113 // Need define variable found first, before detecting define.amd.
27114 if (foundDefine && parse.hasDefineAmd(node)) {
27115 foundDefineAmd = true;
27116
27117 //Stop traversal
27118 return false;
27119 }
27120 });
27121
27122 return foundDefine && foundDefineAmd;
27123 };
27124
27125 /**
27126 * Finds require("") calls inside a CommonJS anonymous module wrapped in a
27127 * define(function(require, exports, module){}) wrapper. These dependencies
27128 * will be added to a modified define() call that lists the dependencies
27129 * on the outside of the function.
27130 * @param {String} fileName
27131 * @param {String|Object} fileContents: a string of contents, or an already
27132 * parsed AST tree.
27133 * @returns {Array} an array of module names that are dependencies. Always
27134 * returns an array, but could be of length zero.
27135 */
27136 parse.getAnonDeps = function (fileName, fileContents) {
27137 var astRoot = typeof fileContents === 'string' ?
27138 esprima.parse(fileContents) : fileContents,
27139 defFunc = this.findAnonDefineFactory(astRoot);
27140
27141 return parse.getAnonDepsFromNode(defFunc);
27142 };
27143
27144 /**
27145 * Finds require("") calls inside a CommonJS anonymous module wrapped
27146 * in a define function, given an AST node for the definition function.
27147 * @param {Node} node the AST node for the definition function.
27148 * @returns {Array} and array of dependency names. Can be of zero length.
27149 */
27150 parse.getAnonDepsFromNode = function (node) {
27151 var deps = [],
27152 funcArgLength;
27153
27154 if (node) {
27155 this.findRequireDepNames(node, deps);
27156
27157 //If no deps, still add the standard CommonJS require, exports,
27158 //module, in that order, to the deps, but only if specified as
27159 //function args. In particular, if exports is used, it is favored
27160 //over the return value of the function, so only add it if asked.
27161 funcArgLength = node.params && node.params.length;
27162 if (funcArgLength) {
27163 deps = (funcArgLength > 1 ? ["require", "exports", "module"] :
27164 ["require"]).concat(deps);
27165 }
27166 }
27167 return deps;
27168 };
27169
27170 parse.isDefineNodeWithArgs = function (node) {
27171 return node && node.type === 'CallExpression' &&
27172 node.callee && node.callee.type === 'Identifier' &&
27173 node.callee.name === 'define' && node[argPropName];
27174 };
27175
27176 /**
27177 * Finds the function in define(function (require, exports, module){});
27178 * @param {Array} node
27179 * @returns {Boolean}
27180 */
27181 parse.findAnonDefineFactory = function (node) {
27182 var match;
27183
27184 traverse(node, function (node) {
27185 var arg0, arg1;
27186
27187 if (parse.isDefineNodeWithArgs(node)) {
27188
27189 //Just the factory function passed to define
27190 arg0 = node[argPropName][0];
27191 if (isFnExpression(arg0)) {
27192 match = arg0;
27193 return false;
27194 }
27195
27196 //A string literal module ID followed by the factory function.
27197 arg1 = node[argPropName][1];
27198 if (arg0.type === 'Literal' && isFnExpression(arg1)) {
27199 match = arg1;
27200 return false;
27201 }
27202 }
27203 });
27204
27205 return match;
27206 };
27207
27208 /**
27209 * Finds any config that is passed to requirejs. That includes calls to
27210 * require/requirejs.config(), as well as require({}, ...) and
27211 * requirejs({}, ...)
27212 * @param {String} fileContents
27213 *
27214 * @returns {Object} a config details object with the following properties:
27215 * - config: {Object} the config object found. Can be undefined if no
27216 * config found.
27217 * - range: {Array} the start index and end index in the contents where
27218 * the config was found. Can be undefined if no config found.
27219 * Can throw an error if the config in the file cannot be evaluated in
27220 * a build context to valid JavaScript.
27221 */
27222 parse.findConfig = function (fileContents) {
27223 /*jslint evil: true */
27224 var jsConfig, foundConfig, stringData, foundRange, quote, quoteMatch,
27225 quoteRegExp = /(:\s|\[\s*)(['"])/,
27226 astRoot = esprima.parse(fileContents, {
27227 loc: true
27228 });
27229
27230 traverse(astRoot, function (node) {
27231 var arg,
27232 requireType = parse.hasRequire(node);
27233
27234 if (requireType && (requireType === 'require' ||
27235 requireType === 'requirejs' ||
27236 requireType === 'requireConfig' ||
27237 requireType === 'requirejsConfig')) {
27238
27239 arg = node[argPropName] && node[argPropName][0];
27240
27241 if (arg && arg.type === 'ObjectExpression') {
27242 stringData = parse.nodeToString(fileContents, arg);
27243 jsConfig = stringData.value;
27244 foundRange = stringData.range;
27245 return false;
27246 }
27247 } else {
27248 arg = parse.getRequireObjectLiteral(node);
27249 if (arg) {
27250 stringData = parse.nodeToString(fileContents, arg);
27251 jsConfig = stringData.value;
27252 foundRange = stringData.range;
27253 return false;
27254 }
27255 }
27256 });
27257
27258 if (jsConfig) {
27259 // Eval the config
27260 quoteMatch = quoteRegExp.exec(jsConfig);
27261 quote = (quoteMatch && quoteMatch[2]) || '"';
27262 foundConfig = eval('(' + jsConfig + ')');
27263 }
27264
27265 return {
27266 config: foundConfig,
27267 range: foundRange,
27268 quote: quote
27269 };
27270 };
27271
27272 /** Returns the node for the object literal assigned to require/requirejs,
27273 * for holding a declarative config.
27274 */
27275 parse.getRequireObjectLiteral = function (node) {
27276 if (node.id && node.id.type === 'Identifier' &&
27277 (node.id.name === 'require' || node.id.name === 'requirejs') &&
27278 node.init && node.init.type === 'ObjectExpression') {
27279 return node.init;
27280 }
27281 };
27282
27283 /**
27284 * Renames require/requirejs/define calls to be ns + '.' + require/requirejs/define
27285 * Does *not* do .config calls though. See pragma.namespace for the complete
27286 * set of namespace transforms. This function is used because require calls
27287 * inside a define() call should not be renamed, so a simple regexp is not
27288 * good enough.
27289 * @param {String} fileContents the contents to transform.
27290 * @param {String} ns the namespace, *not* including trailing dot.
27291 * @return {String} the fileContents with the namespace applied
27292 */
27293 parse.renameNamespace = function (fileContents, ns) {
27294 var lines,
27295 locs = [],
27296 astRoot = esprima.parse(fileContents, {
27297 loc: true
27298 });
27299
27300 parse.recurse(astRoot, function (callName, config, name, deps, node) {
27301 locs.push(node.loc);
27302 //Do not recurse into define functions, they should be using
27303 //local defines.
27304 return callName !== 'define';
27305 }, {});
27306
27307 if (locs.length) {
27308 lines = fileContents.split('\n');
27309
27310 //Go backwards through the found locs, adding in the namespace name
27311 //in front.
27312 locs.reverse();
27313 locs.forEach(function (loc) {
27314 var startIndex = loc.start.column,
27315 //start.line is 1-based, not 0 based.
27316 lineIndex = loc.start.line - 1,
27317 line = lines[lineIndex];
27318
27319 lines[lineIndex] = line.substring(0, startIndex) +
27320 ns + '.' +
27321 line.substring(startIndex,
27322 line.length);
27323 });
27324
27325 fileContents = lines.join('\n');
27326 }
27327
27328 return fileContents;
27329 };
27330
27331 /**
27332 * Finds all dependencies specified in dependency arrays and inside
27333 * simplified commonjs wrappers.
27334 * @param {String} fileName
27335 * @param {String} fileContents
27336 *
27337 * @returns {Array} an array of dependency strings. The dependencies
27338 * have not been normalized, they may be relative IDs.
27339 */
27340 parse.findDependencies = function (fileName, fileContents, options) {
27341 var dependencies = [],
27342 astRoot = esprima.parse(fileContents);
27343
27344 parse.recurse(astRoot, function (callName, config, name, deps) {
27345 if (deps) {
27346 dependencies = dependencies.concat(deps);
27347 }
27348 }, options);
27349
27350 return dependencies;
27351 };
27352
27353 /**
27354 * Finds only CJS dependencies, ones that are the form
27355 * require('stringLiteral')
27356 */
27357 parse.findCjsDependencies = function (fileName, fileContents) {
27358 var dependencies = [];
27359
27360 traverse(esprima.parse(fileContents), function (node) {
27361 var arg;
27362
27363 if (node && node.type === 'CallExpression' && node.callee &&
27364 node.callee.type === 'Identifier' &&
27365 node.callee.name === 'require' && node[argPropName] &&
27366 node[argPropName].length === 1) {
27367 arg = node[argPropName][0];
27368 if (arg.type === 'Literal') {
27369 dependencies.push(arg.value);
27370 }
27371 }
27372 });
27373
27374 return dependencies;
27375 };
27376
27377 //function define() {}
27378 parse.hasDefDefine = function (node) {
27379 return node.type === 'FunctionDeclaration' && node.id &&
27380 node.id.type === 'Identifier' && node.id.name === 'define';
27381 };
27382
27383 //define.amd = ...
27384 parse.hasDefineAmd = function (node) {
27385 return node && node.type === 'AssignmentExpression' &&
27386 node.left && node.left.type === 'MemberExpression' &&
27387 node.left.object && node.left.object.name === 'define' &&
27388 node.left.property && node.left.property.name === 'amd';
27389 };
27390
27391 //define.amd reference, as in: if (define.amd)
27392 parse.refsDefineAmd = function (node) {
27393 return node && node.type === 'MemberExpression' &&
27394 node.object && node.object.name === 'define' &&
27395 node.object.type === 'Identifier' &&
27396 node.property && node.property.name === 'amd' &&
27397 node.property.type === 'Identifier';
27398 };
27399
27400 //require(), requirejs(), require.config() and requirejs.config()
27401 parse.hasRequire = function (node) {
27402 var callName,
27403 c = node && node.callee;
27404
27405 if (node && node.type === 'CallExpression' && c) {
27406 if (c.type === 'Identifier' &&
27407 (c.name === 'require' ||
27408 c.name === 'requirejs')) {
27409 //A require/requirejs({}, ...) call
27410 callName = c.name;
27411 } else if (c.type === 'MemberExpression' &&
27412 c.object &&
27413 c.object.type === 'Identifier' &&
27414 (c.object.name === 'require' ||
27415 c.object.name === 'requirejs') &&
27416 c.property && c.property.name === 'config') {
27417 // require/requirejs.config({}) call
27418 callName = c.object.name + 'Config';
27419 }
27420 }
27421
27422 return callName;
27423 };
27424
27425 //define()
27426 parse.hasDefine = function (node) {
27427 return node && node.type === 'CallExpression' && node.callee &&
27428 node.callee.type === 'Identifier' &&
27429 node.callee.name === 'define';
27430 };
27431
27432 /**
27433 * If there is a named define in the file, returns the name. Does not
27434 * scan for mulitple names, just the first one.
27435 */
27436 parse.getNamedDefine = function (fileContents) {
27437 var name;
27438 traverse(esprima.parse(fileContents), function (node) {
27439 if (node && node.type === 'CallExpression' && node.callee &&
27440 node.callee.type === 'Identifier' &&
27441 node.callee.name === 'define' &&
27442 node[argPropName] && node[argPropName][0] &&
27443 node[argPropName][0].type === 'Literal') {
27444 name = node[argPropName][0].value;
27445 return false;
27446 }
27447 });
27448
27449 return name;
27450 };
27451
27452 /**
27453 * Determines if define(), require({}|[]) or requirejs was called in the
27454 * file. Also finds out if define() is declared and if define.amd is called.
27455 */
27456 parse.usesAmdOrRequireJs = function (fileName, fileContents) {
27457 var uses;
27458
27459 traverse(esprima.parse(fileContents), function (node) {
27460 var type, callName, arg;
27461
27462 if (parse.hasDefDefine(node)) {
27463 //function define() {}
27464 type = 'declaresDefine';
27465 } else if (parse.hasDefineAmd(node)) {
27466 type = 'defineAmd';
27467 } else {
27468 callName = parse.hasRequire(node);
27469 if (callName) {
27470 arg = node[argPropName] && node[argPropName][0];
27471 if (arg && (arg.type === 'ObjectExpression' ||
27472 arg.type === 'ArrayExpression')) {
27473 type = callName;
27474 }
27475 } else if (parse.hasDefine(node)) {
27476 type = 'define';
27477 }
27478 }
27479
27480 if (type) {
27481 if (!uses) {
27482 uses = {};
27483 }
27484 uses[type] = true;
27485 }
27486 });
27487
27488 return uses;
27489 };
27490
27491 /**
27492 * Determines if require(''), exports.x =, module.exports =,
27493 * __dirname, __filename are used. So, not strictly traditional CommonJS,
27494 * also checks for Node variants.
27495 */
27496 parse.usesCommonJs = function (fileName, fileContents) {
27497 var uses = null,
27498 assignsExports = false;
27499
27500
27501 traverse(esprima.parse(fileContents), function (node) {
27502 var type,
27503 exp = node.expression || node.init;
27504
27505 if (node.type === 'Identifier' &&
27506 (node.name === '__dirname' || node.name === '__filename')) {
27507 type = node.name.substring(2);
27508 } else if (node.type === 'VariableDeclarator' && node.id &&
27509 node.id.type === 'Identifier' &&
27510 node.id.name === 'exports') {
27511 //Hmm, a variable assignment for exports, so does not use cjs
27512 //exports.
27513 type = 'varExports';
27514 } else if (exp && exp.type === 'AssignmentExpression' && exp.left &&
27515 exp.left.type === 'MemberExpression' && exp.left.object) {
27516 if (exp.left.object.name === 'module' && exp.left.property &&
27517 exp.left.property.name === 'exports') {
27518 type = 'moduleExports';
27519 } else if (exp.left.object.name === 'exports' &&
27520 exp.left.property) {
27521 type = 'exports';
27522 }
27523
27524 } else if (node && node.type === 'CallExpression' && node.callee &&
27525 node.callee.type === 'Identifier' &&
27526 node.callee.name === 'require' && node[argPropName] &&
27527 node[argPropName].length === 1 &&
27528 node[argPropName][0].type === 'Literal') {
27529 type = 'require';
27530 }
27531
27532 if (type) {
27533 if (type === 'varExports') {
27534 assignsExports = true;
27535 } else if (type !== 'exports' || !assignsExports) {
27536 if (!uses) {
27537 uses = {};
27538 }
27539 uses[type] = true;
27540 }
27541 }
27542 });
27543
27544 return uses;
27545 };
27546
27547
27548 parse.findRequireDepNames = function (node, deps) {
27549 traverse(node, function (node) {
27550 var arg;
27551
27552 if (node && node.type === 'CallExpression' && node.callee &&
27553 node.callee.type === 'Identifier' &&
27554 node.callee.name === 'require' &&
27555 node[argPropName] && node[argPropName].length === 1) {
27556
27557 arg = node[argPropName][0];
27558 if (arg.type === 'Literal') {
27559 deps.push(arg.value);
27560 }
27561 }
27562 });
27563 };
27564
27565 /**
27566 * Determines if a specific node is a valid require or define/require.def
27567 * call.
27568 * @param {Array} node
27569 * @param {Function} onMatch a function to call when a match is found.
27570 * It is passed the match name, and the config, name, deps possible args.
27571 * The config, name and deps args are not normalized.
27572 * @param {Object} fnExpScope an object whose keys are all function
27573 * expression identifiers that should be in scope. Useful for UMD wrapper
27574 * detection to avoid parsing more into the wrapped UMD code.
27575 *
27576 * @returns {String} a JS source string with the valid require/define call.
27577 * Otherwise null.
27578 */
27579 parse.parseNode = function (node, onMatch, fnExpScope) {
27580 var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode,
27581 args = node && node[argPropName],
27582 callName = parse.hasRequire(node),
27583 isUmd = false;
27584
27585 if (callName === 'require' || callName === 'requirejs') {
27586 //A plain require/requirejs call
27587 arg = node[argPropName] && node[argPropName][0];
27588 if (arg && arg.type !== 'ArrayExpression') {
27589 if (arg.type === 'ObjectExpression') {
27590 //A config call, try the second arg.
27591 arg = node[argPropName][1];
27592 }
27593 }
27594
27595 deps = getValidDeps(arg);
27596 if (!deps) {
27597 return;
27598 }
27599
27600 return onMatch("require", null, null, deps, node);
27601 } else if (parse.hasDefine(node) && args && args.length) {
27602 name = args[0];
27603 deps = args[1];
27604 factory = args[2];
27605
27606 if (name.type === 'ArrayExpression') {
27607 //No name, adjust args
27608 factory = deps;
27609 deps = name;
27610 name = null;
27611 } else if (isFnExpression(name)) {
27612 //Just the factory, no name or deps
27613 factory = name;
27614 name = deps = null;
27615 } else if (name.type === 'Identifier' && args.length === 1 &&
27616 hasProp(fnExpScope, name.name)) {
27617 //define(e) where e is a UMD identifier for the factory
27618 //function.
27619 isUmd = true;
27620 factory = name;
27621 name = null;
27622 } else if (name.type !== 'Literal') {
27623 //An object literal, just null out
27624 name = deps = factory = null;
27625 }
27626
27627 if (name && name.type === 'Literal' && deps) {
27628 if (isFnExpression(deps)) {
27629 //deps is the factory
27630 factory = deps;
27631 deps = null;
27632 } else if (deps.type === 'ObjectExpression') {
27633 //deps is object literal, null out
27634 deps = factory = null;
27635 } else if (deps.type === 'Identifier') {
27636 if (args.length === 2) {
27637 //define('id', factory)
27638 deps = factory = null;
27639 } else if (args.length === 3 && isFnExpression(factory)) {
27640 //define('id', depsIdentifier, factory)
27641 //Since identifier, cannot know the deps, but do not
27642 //error out, assume they are taken care of outside of
27643 //static parsing.
27644 deps = null;
27645 }
27646 }
27647 }
27648
27649 if (deps && deps.type === 'ArrayExpression') {
27650 deps = getValidDeps(deps);
27651 } else if (isFnExpression(factory)) {
27652 //If no deps and a factory function, could be a commonjs sugar
27653 //wrapper, scan the function for dependencies.
27654 cjsDeps = parse.getAnonDepsFromNode(factory);
27655 if (cjsDeps.length) {
27656 deps = cjsDeps;
27657 }
27658 } else if (deps || (factory && !isUmd)) {
27659 //Does not match the shape of an AMD call.
27660 return;
27661 }
27662
27663 //Just save off the name as a string instead of an AST object.
27664 if (name && name.type === 'Literal') {
27665 name = name.value;
27666 }
27667
27668 return onMatch("define", null, name, deps, node,
27669 (factory && factory.type === 'Identifier' ? factory.name : undefined),
27670 fnExpScope);
27671 } else if (node.type === 'CallExpression' && node.callee &&
27672 isFnExpression(node.callee) &&
27673 node.callee.body && node.callee.body.body &&
27674 node.callee.body.body.length === 1 &&
27675 node.callee.body.body[0].type === 'IfStatement') {
27676 bodyNode = node.callee.body.body[0];
27677 //Look for a define(Identifier) case, but only if inside an
27678 //if that has a define.amd test
27679 if (bodyNode.consequent && bodyNode.consequent.body) {
27680 exp = bodyNode.consequent.body[0];
27681 if (exp.type === 'ExpressionStatement' && exp.expression &&
27682 parse.hasDefine(exp.expression) &&
27683 exp.expression.arguments &&
27684 exp.expression.arguments.length === 1 &&
27685 exp.expression.arguments[0].type === 'Identifier') {
27686
27687 //Calls define(Identifier) as first statement in body.
27688 //Confirm the if test references define.amd
27689 traverse(bodyNode.test, function (node) {
27690 if (parse.refsDefineAmd(node)) {
27691 refsDefine = true;
27692 return false;
27693 }
27694 });
27695
27696 if (refsDefine) {
27697 return onMatch("define", null, null, null, exp.expression,
27698 exp.expression.arguments[0].name, fnExpScope);
27699 }
27700 }
27701 }
27702 }
27703 };
27704
27705 /**
27706 * Converts an AST node into a JS source string by extracting
27707 * the node's location from the given contents string. Assumes
27708 * esprima.parse() with loc was done.
27709 * @param {String} contents
27710 * @param {Object} node
27711 * @returns {String} a JS source string.
27712 */
27713 parse.nodeToString = function (contents, node) {
27714 var extracted,
27715 loc = node.loc,
27716 lines = contents.split('\n'),
27717 firstLine = loc.start.line > 1 ?
27718 lines.slice(0, loc.start.line - 1).join('\n') + '\n' :
27719 '',
27720 preamble = firstLine +
27721 lines[loc.start.line - 1].substring(0, loc.start.column);
27722
27723 if (loc.start.line === loc.end.line) {
27724 extracted = lines[loc.start.line - 1].substring(loc.start.column,
27725 loc.end.column);
27726 } else {
27727 extracted = lines[loc.start.line - 1].substring(loc.start.column) +
27728 '\n' +
27729 lines.slice(loc.start.line, loc.end.line - 1).join('\n') +
27730 '\n' +
27731 lines[loc.end.line - 1].substring(0, loc.end.column);
27732 }
27733
27734 return {
27735 value: extracted,
27736 range: [
27737 preamble.length,
27738 preamble.length + extracted.length
27739 ]
27740 };
27741 };
27742
27743 /**
27744 * Extracts license comments from JS text.
27745 * @param {String} fileName
27746 * @param {String} contents
27747 * @returns {String} a string of license comments.
27748 */
27749 parse.getLicenseComments = function (fileName, contents) {
27750 var commentNode, refNode, subNode, value, i, j,
27751 //xpconnect's Reflect does not support comment or range, but
27752 //prefer continued operation vs strict parity of operation,
27753 //as license comments can be expressed in other ways, like
27754 //via wrap args, or linked via sourcemaps.
27755 ast = esprima.parse(contents, {
27756 comment: true,
27757 range: true
27758 }),
27759 result = '',
27760 existsMap = {},
27761 lineEnd = contents.indexOf('\r') === -1 ? '\n' : '\r\n';
27762
27763 if (ast.comments) {
27764 for (i = 0; i < ast.comments.length; i++) {
27765 commentNode = ast.comments[i];
27766
27767 if (commentNode.type === 'Line') {
27768 value = '//' + commentNode.value + lineEnd;
27769 refNode = commentNode;
27770
27771 if (i + 1 >= ast.comments.length) {
27772 value += lineEnd;
27773 } else {
27774 //Look for immediately adjacent single line comments
27775 //since it could from a multiple line comment made out
27776 //of single line comments. Like this comment.
27777 for (j = i + 1; j < ast.comments.length; j++) {
27778 subNode = ast.comments[j];
27779 if (subNode.type === 'Line' &&
27780 subNode.range[0] === refNode.range[1] + 1) {
27781 //Adjacent single line comment. Collect it.
27782 value += '//' + subNode.value + lineEnd;
27783 refNode = subNode;
27784 } else {
27785 //No more single line comment blocks. Break out
27786 //and continue outer looping.
27787 break;
27788 }
27789 }
27790 value += lineEnd;
27791 i = j - 1;
27792 }
27793 } else {
27794 value = '/*' + commentNode.value + '*/' + lineEnd + lineEnd;
27795 }
27796
27797 if (!existsMap[value] && (value.indexOf('license') !== -1 ||
27798 (commentNode.type === 'Block' &&
27799 value.indexOf('/*!') === 0) ||
27800 value.indexOf('opyright') !== -1 ||
27801 value.indexOf('(c)') !== -1)) {
27802
27803 result += value;
27804 existsMap[value] = true;
27805 }
27806
27807 }
27808 }
27809
27810 return result;
27811 };
27812
27813 return parse;
27814});
27815/**
27816 * @license Copyright (c) 2012-2014, The Dojo Foundation All Rights Reserved.
27817 * Available via the MIT or new BSD license.
27818 * see: http://github.com/jrburke/requirejs for details
27819 */
27820
27821/*global define */
27822
27823define('transform', [ './esprimaAdapter', './parse', 'logger', 'lang'],
27824function (esprima, parse, logger, lang) {
27825 'use strict';
27826 var transform,
27827 baseIndentRegExp = /^([ \t]+)/,
27828 indentRegExp = /\{[\r\n]+([ \t]+)/,
27829 keyRegExp = /^[_A-Za-z]([A-Za-z\d_]*)$/,
27830 bulkIndentRegExps = {
27831 '\n': /\n/g,
27832 '\r\n': /\r\n/g
27833 };
27834
27835 function applyIndent(str, indent, lineReturn) {
27836 var regExp = bulkIndentRegExps[lineReturn];
27837 return str.replace(regExp, '$&' + indent);
27838 }
27839
27840 transform = {
27841 toTransport: function (namespace, moduleName, path, contents, onFound, options) {
27842 options = options || {};
27843
27844 var astRoot, contentLines, modLine,
27845 foundAnon,
27846 scanCount = 0,
27847 scanReset = false,
27848 defineInfos = [],
27849 applySourceUrl = function (contents) {
27850 if (options.useSourceUrl) {
27851 contents = 'eval("' + lang.jsEscape(contents) +
27852 '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') +
27853 path +
27854 '");\n';
27855 }
27856 return contents;
27857 };
27858
27859 try {
27860 astRoot = esprima.parse(contents, {
27861 loc: true
27862 });
27863 } catch (e) {
27864 logger.trace('toTransport skipping ' + path + ': ' +
27865 e.toString());
27866 return contents;
27867 }
27868
27869 //Find the define calls and their position in the files.
27870 parse.traverse(astRoot, function (node) {
27871 var args, firstArg, firstArgLoc, factoryNode,
27872 needsId, depAction, foundId, init,
27873 sourceUrlData, range,
27874 namespaceExists = false;
27875
27876 // If a bundle script with a define declaration, do not
27877 // parse any further at this level. Likely a built layer
27878 // by some other tool.
27879 if (node.type === 'VariableDeclarator' &&
27880 node.id && node.id.name === 'define' &&
27881 node.id.type === 'Identifier') {
27882 init = node.init;
27883 if (init && init.callee &&
27884 init.callee.type === 'CallExpression' &&
27885 init.callee.callee &&
27886 init.callee.callee.type === 'Identifier' &&
27887 init.callee.callee.name === 'require' &&
27888 init.callee.arguments && init.callee.arguments.length === 1 &&
27889 init.callee.arguments[0].type === 'Literal' &&
27890 init.callee.arguments[0].value &&
27891 init.callee.arguments[0].value.indexOf('amdefine') !== -1) {
27892 // the var define = require('amdefine')(module) case,
27893 // keep going in that case.
27894 } else {
27895 return false;
27896 }
27897 }
27898
27899 namespaceExists = namespace &&
27900 node.type === 'CallExpression' &&
27901 node.callee && node.callee.object &&
27902 node.callee.object.type === 'Identifier' &&
27903 node.callee.object.name === namespace &&
27904 node.callee.property.type === 'Identifier' &&
27905 node.callee.property.name === 'define';
27906
27907 if (namespaceExists || parse.isDefineNodeWithArgs(node)) {
27908 //The arguments are where its at.
27909 args = node.arguments;
27910 if (!args || !args.length) {
27911 return;
27912 }
27913
27914 firstArg = args[0];
27915 firstArgLoc = firstArg.loc;
27916
27917 if (args.length === 1) {
27918 if (firstArg.type === 'Identifier') {
27919 //The define(factory) case, but
27920 //only allow it if one Identifier arg,
27921 //to limit impact of false positives.
27922 needsId = true;
27923 depAction = 'empty';
27924 } else if (parse.isFnExpression(firstArg)) {
27925 //define(function(){})
27926 factoryNode = firstArg;
27927 needsId = true;
27928 depAction = 'scan';
27929 } else if (firstArg.type === 'ObjectExpression') {
27930 //define({});
27931 needsId = true;
27932 depAction = 'skip';
27933 } else if (firstArg.type === 'Literal' &&
27934 typeof firstArg.value === 'number') {
27935 //define('12345');
27936 needsId = true;
27937 depAction = 'skip';
27938 } else if (firstArg.type === 'UnaryExpression' &&
27939 firstArg.operator === '-' &&
27940 firstArg.argument &&
27941 firstArg.argument.type === 'Literal' &&
27942 typeof firstArg.argument.value === 'number') {
27943 //define('-12345');
27944 needsId = true;
27945 depAction = 'skip';
27946 } else if (firstArg.type === 'MemberExpression' &&
27947 firstArg.object &&
27948 firstArg.property &&
27949 firstArg.property.type === 'Identifier') {
27950 //define(this.key);
27951 needsId = true;
27952 depAction = 'empty';
27953 }
27954 } else if (firstArg.type === 'ArrayExpression') {
27955 //define([], ...);
27956 needsId = true;
27957 depAction = 'skip';
27958 } else if (firstArg.type === 'Literal' &&
27959 typeof firstArg.value === 'string') {
27960 //define('string', ....)
27961 //Already has an ID.
27962 needsId = false;
27963 if (args.length === 2 &&
27964 parse.isFnExpression(args[1])) {
27965 //Needs dependency scanning.
27966 factoryNode = args[1];
27967 depAction = 'scan';
27968 } else {
27969 depAction = 'skip';
27970 }
27971 } else {
27972 //Unknown define entity, keep looking, even
27973 //in the subtree for this node.
27974 return;
27975 }
27976
27977 range = {
27978 foundId: foundId,
27979 needsId: needsId,
27980 depAction: depAction,
27981 namespaceExists: namespaceExists,
27982 node: node,
27983 defineLoc: node.loc,
27984 firstArgLoc: firstArgLoc,
27985 factoryNode: factoryNode,
27986 sourceUrlData: sourceUrlData
27987 };
27988
27989 //Only transform ones that do not have IDs. If it has an
27990 //ID but no dependency array, assume it is something like
27991 //a phonegap implementation, that has its own internal
27992 //define that cannot handle dependency array constructs,
27993 //and if it is a named module, then it means it has been
27994 //set for transport form.
27995 if (range.needsId) {
27996 if (foundAnon) {
27997 logger.trace(path + ' has more than one anonymous ' +
27998 'define. May be a built file from another ' +
27999 'build system like, Ender. Skipping normalization.');
28000 defineInfos = [];
28001 return false;
28002 } else {
28003 foundAnon = range;
28004 defineInfos.push(range);
28005 }
28006 } else if (depAction === 'scan') {
28007 scanCount += 1;
28008 if (scanCount > 1) {
28009 //Just go back to an array that just has the
28010 //anon one, since this is an already optimized
28011 //file like the phonegap one.
28012 if (!scanReset) {
28013 defineInfos = foundAnon ? [foundAnon] : [];
28014 scanReset = true;
28015 }
28016 } else {
28017 defineInfos.push(range);
28018 }
28019 }
28020 }
28021 });
28022
28023
28024 if (!defineInfos.length) {
28025 return applySourceUrl(contents);
28026 }
28027
28028 //Reverse the matches, need to start from the bottom of
28029 //the file to modify it, so that the ranges are still true
28030 //further up.
28031 defineInfos.reverse();
28032
28033 contentLines = contents.split('\n');
28034
28035 modLine = function (loc, contentInsertion) {
28036 var startIndex = loc.start.column,
28037 //start.line is 1-based, not 0 based.
28038 lineIndex = loc.start.line - 1,
28039 line = contentLines[lineIndex];
28040 contentLines[lineIndex] = line.substring(0, startIndex) +
28041 contentInsertion +
28042 line.substring(startIndex,
28043 line.length);
28044 };
28045
28046 defineInfos.forEach(function (info) {
28047 var deps,
28048 contentInsertion = '',
28049 depString = '';
28050
28051 //Do the modifications "backwards", in other words, start with the
28052 //one that is farthest down and work up, so that the ranges in the
28053 //defineInfos still apply. So that means deps, id, then namespace.
28054 if (info.needsId && moduleName) {
28055 contentInsertion += "'" + moduleName + "',";
28056 }
28057
28058 if (info.depAction === 'scan') {
28059 deps = parse.getAnonDepsFromNode(info.factoryNode);
28060
28061 if (deps.length) {
28062 depString = '[' + deps.map(function (dep) {
28063 return "'" + dep + "'";
28064 }) + ']';
28065 } else {
28066 depString = '[]';
28067 }
28068 depString += ',';
28069
28070 if (info.factoryNode) {
28071 //Already have a named module, need to insert the
28072 //dependencies after the name.
28073 modLine(info.factoryNode.loc, depString);
28074 } else {
28075 contentInsertion += depString;
28076 }
28077 }
28078
28079 if (contentInsertion) {
28080 modLine(info.firstArgLoc, contentInsertion);
28081 }
28082
28083 //Do namespace last so that ui does not mess upthe parenRange
28084 //used above.
28085 if (namespace && !info.namespaceExists) {
28086 modLine(info.defineLoc, namespace + '.');
28087 }
28088
28089 //Notify any listener for the found info
28090 if (onFound) {
28091 onFound(info);
28092 }
28093 });
28094
28095 contents = contentLines.join('\n');
28096
28097 return applySourceUrl(contents);
28098 },
28099
28100 /**
28101 * Modify the contents of a require.config/requirejs.config call. This
28102 * call will LOSE any existing comments that are in the config string.
28103 *
28104 * @param {String} fileContents String that may contain a config call
28105 * @param {Function} onConfig Function called when the first config
28106 * call is found. It will be passed an Object which is the current
28107 * config, and the onConfig function should return an Object to use
28108 * as the config.
28109 * @return {String} the fileContents with the config changes applied.
28110 */
28111 modifyConfig: function (fileContents, onConfig) {
28112 var details = parse.findConfig(fileContents),
28113 config = details.config;
28114
28115 if (config) {
28116 config = onConfig(config);
28117 if (config) {
28118 return transform.serializeConfig(config,
28119 fileContents,
28120 details.range[0],
28121 details.range[1],
28122 {
28123 quote: details.quote
28124 });
28125 }
28126 }
28127
28128 return fileContents;
28129 },
28130
28131 serializeConfig: function (config, fileContents, start, end, options) {
28132 //Calculate base level of indent
28133 var indent, match, configString, outDentRegExp,
28134 baseIndent = '',
28135 startString = fileContents.substring(0, start),
28136 existingConfigString = fileContents.substring(start, end),
28137 lineReturn = existingConfigString.indexOf('\r') === -1 ? '\n' : '\r\n',
28138 lastReturnIndex = startString.lastIndexOf('\n');
28139
28140 //Get the basic amount of indent for the require config call.
28141 if (lastReturnIndex === -1) {
28142 lastReturnIndex = 0;
28143 }
28144
28145 match = baseIndentRegExp.exec(startString.substring(lastReturnIndex + 1, start));
28146 if (match && match[1]) {
28147 baseIndent = match[1];
28148 }
28149
28150 //Calculate internal indentation for config
28151 match = indentRegExp.exec(existingConfigString);
28152 if (match && match[1]) {
28153 indent = match[1];
28154 }
28155
28156 if (!indent || indent.length < baseIndent) {
28157 indent = ' ';
28158 } else {
28159 indent = indent.substring(baseIndent.length);
28160 }
28161
28162 outDentRegExp = new RegExp('(' + lineReturn + ')' + indent, 'g');
28163
28164 configString = transform.objectToString(config, {
28165 indent: indent,
28166 lineReturn: lineReturn,
28167 outDentRegExp: outDentRegExp,
28168 quote: options && options.quote
28169 });
28170
28171 //Add in the base indenting level.
28172 configString = applyIndent(configString, baseIndent, lineReturn);
28173
28174 return startString + configString + fileContents.substring(end);
28175 },
28176
28177 /**
28178 * Tries converting a JS object to a string. This will likely suck, and
28179 * is tailored to the type of config expected in a loader config call.
28180 * So, hasOwnProperty fields, strings, numbers, arrays and functions,
28181 * no weird recursively referenced stuff.
28182 * @param {Object} obj the object to convert
28183 * @param {Object} options options object with the following values:
28184 * {String} indent the indentation to use for each level
28185 * {String} lineReturn the type of line return to use
28186 * {outDentRegExp} outDentRegExp the regexp to use to outdent functions
28187 * {String} quote the quote type to use, ' or ". Optional. Default is "
28188 * @param {String} totalIndent the total indent to print for this level
28189 * @return {String} a string representation of the object.
28190 */
28191 objectToString: function (obj, options, totalIndent) {
28192 var startBrace, endBrace, nextIndent,
28193 first = true,
28194 value = '',
28195 lineReturn = options.lineReturn,
28196 indent = options.indent,
28197 outDentRegExp = options.outDentRegExp,
28198 quote = options.quote || '"';
28199
28200 totalIndent = totalIndent || '';
28201 nextIndent = totalIndent + indent;
28202
28203 if (obj === null) {
28204 value = 'null';
28205 } else if (obj === undefined) {
28206 value = 'undefined';
28207 } else if (typeof obj === 'number' || typeof obj === 'boolean') {
28208 value = obj;
28209 } else if (typeof obj === 'string') {
28210 //Use double quotes in case the config may also work as JSON.
28211 value = quote + lang.jsEscape(obj) + quote;
28212 } else if (lang.isArray(obj)) {
28213 lang.each(obj, function (item, i) {
28214 value += (i !== 0 ? ',' + lineReturn : '' ) +
28215 nextIndent +
28216 transform.objectToString(item,
28217 options,
28218 nextIndent);
28219 });
28220
28221 startBrace = '[';
28222 endBrace = ']';
28223 } else if (lang.isFunction(obj) || lang.isRegExp(obj)) {
28224 //The outdent regexp just helps pretty up the conversion
28225 //just in node. Rhino strips comments and does a different
28226 //indent scheme for Function toString, so not really helpful
28227 //there.
28228 value = obj.toString().replace(outDentRegExp, '$1');
28229 } else {
28230 //An object
28231 lang.eachProp(obj, function (v, prop) {
28232 value += (first ? '': ',' + lineReturn) +
28233 nextIndent +
28234 (keyRegExp.test(prop) ? prop : quote + lang.jsEscape(prop) + quote )+
28235 ': ' +
28236 transform.objectToString(v,
28237 options,
28238 nextIndent);
28239 first = false;
28240 });
28241 startBrace = '{';
28242 endBrace = '}';
28243 }
28244
28245 if (startBrace) {
28246 value = startBrace +
28247 lineReturn +
28248 value +
28249 lineReturn + totalIndent +
28250 endBrace;
28251 }
28252
28253 return value;
28254 }
28255 };
28256
28257 return transform;
28258});
28259/**
28260 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
28261 * Available via the MIT or new BSD license.
28262 * see: http://github.com/jrburke/requirejs for details
28263 */
28264
28265/*jslint regexp: true, plusplus: true */
28266/*global define: false */
28267
28268define('pragma', ['parse', 'logger'], function (parse, logger) {
28269 'use strict';
28270 function Temp() {}
28271
28272 function create(obj, mixin) {
28273 Temp.prototype = obj;
28274 var temp = new Temp(), prop;
28275
28276 //Avoid any extra memory hanging around
28277 Temp.prototype = null;
28278
28279 if (mixin) {
28280 for (prop in mixin) {
28281 if (mixin.hasOwnProperty(prop) && !temp.hasOwnProperty(prop)) {
28282 temp[prop] = mixin[prop];
28283 }
28284 }
28285 }
28286
28287 return temp; // Object
28288 }
28289
28290 var pragma = {
28291 conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/,
28292 useStrictRegExp: /(^|[^{]\r?\n)['"]use strict['"];/g,
28293 hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
28294 configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g,
28295 nsWrapRegExp: /\/\*requirejs namespace: true \*\//,
28296 apiDefRegExp: /var requirejs,\s*require,\s*define;/,
28297 defineCheckRegExp: /typeof(\s+|\s*\(\s*)define(\s*\))?\s*===?\s*["']function["']\s*&&\s*define\s*\.\s*amd/g,
28298 defineStringCheckRegExp: /typeof\s+define\s*===?\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g,
28299 defineTypeFirstCheckRegExp: /\s*["']function["']\s*==(=?)\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g,
28300 defineJQueryRegExp: /typeof\s+define\s*===?\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g,
28301 defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
28302 defineTernaryRegExp: /typeof\s+define\s*===?\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/,
28303 defineExistsRegExp: /\s+typeof\s+define\s*!==?\s*['"]undefined["']\s*/,
28304 defineExistsAndAmdRegExp: /typeof\s+define\s*!==?\s*['"]undefined["']\s*&&\s*define\s*\.\s*amd\s*/,
28305 amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*['"]function['"]\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g,
28306
28307 removeStrict: function (contents, config) {
28308 return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, '$1');
28309 },
28310
28311 namespace: function (fileContents, ns, onLifecycleName) {
28312 if (ns) {
28313 //Namespace require/define calls
28314 fileContents = fileContents.replace(pragma.configRegExp, '$1' + ns + '.$2$3(');
28315
28316
28317 fileContents = parse.renameNamespace(fileContents, ns);
28318
28319 //Namespace define ternary use:
28320 fileContents = fileContents.replace(pragma.defineTernaryRegExp,
28321 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd ? " + ns + ".define");
28322
28323 //Namespace define jquery use:
28324 fileContents = fileContents.replace(pragma.defineJQueryRegExp,
28325 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd && " + ns + ".define.amd.jQuery");
28326
28327 //Namespace has.js define use:
28328 fileContents = fileContents.replace(pragma.defineHasRegExp,
28329 "typeof " + ns + ".define === 'function' && typeof " + ns + ".define.amd === 'object' && " + ns + ".define.amd");
28330
28331 //Namespace async.js define use:
28332 fileContents = fileContents.replace(pragma.defineExistsAndAmdRegExp,
28333 "typeof " + ns + ".define !== 'undefined' && " + ns + ".define.amd");
28334
28335 //Namespace define checks.
28336 //Do these ones last, since they are a subset of the more specific
28337 //checks above.
28338 fileContents = fileContents.replace(pragma.defineCheckRegExp,
28339 "typeof " + ns + ".define === 'function' && " + ns + ".define.amd");
28340 fileContents = fileContents.replace(pragma.defineStringCheckRegExp,
28341 "typeof " + ns + ".define === 'function' && " + ns + ".define['amd']");
28342 fileContents = fileContents.replace(pragma.defineTypeFirstCheckRegExp,
28343 "'function' === typeof " + ns + ".define && " + ns + ".define.amd");
28344 fileContents = fileContents.replace(pragma.defineExistsRegExp,
28345 "typeof " + ns + ".define !== 'undefined'");
28346
28347 //Check for require.js with the require/define definitions
28348 if (pragma.apiDefRegExp.test(fileContents) &&
28349 fileContents.indexOf("if (!" + ns + " || !" + ns + ".requirejs)") === -1) {
28350 //Wrap the file contents in a typeof check, and a function
28351 //to contain the API globals.
28352 fileContents = "var " + ns + ";(function () { if (!" + ns + " || !" + ns + ".requirejs) {\n" +
28353 "if (!" + ns + ") { " + ns + ' = {}; } else { require = ' + ns + '; }\n' +
28354 fileContents +
28355 "\n" +
28356 ns + ".requirejs = requirejs;" +
28357 ns + ".require = require;" +
28358 ns + ".define = define;\n" +
28359 "}\n}());";
28360 }
28361
28362 //Finally, if the file wants a special wrapper because it ties
28363 //in to the requirejs internals in a way that would not fit
28364 //the above matches, do that. Look for /*requirejs namespace: true*/
28365 if (pragma.nsWrapRegExp.test(fileContents)) {
28366 //Remove the pragma.
28367 fileContents = fileContents.replace(pragma.nsWrapRegExp, '');
28368
28369 //Alter the contents.
28370 fileContents = '(function () {\n' +
28371 'var require = ' + ns + '.require,' +
28372 'requirejs = ' + ns + '.requirejs,' +
28373 'define = ' + ns + '.define;\n' +
28374 fileContents +
28375 '\n}());';
28376 }
28377 }
28378
28379 return fileContents;
28380 },
28381
28382 /**
28383 * processes the fileContents for some //>> conditional statements
28384 */
28385 process: function (fileName, fileContents, config, onLifecycleName, pluginCollector) {
28386 /*jslint evil: true */
28387 var foundIndex = -1, startIndex = 0, lineEndIndex, conditionLine,
28388 matches, type, marker, condition, isTrue, endRegExp, endMatches,
28389 endMarkerIndex, shouldInclude, startLength, lifecycleHas, deps,
28390 i, dep, moduleName, collectorMod,
28391 lifecyclePragmas, pragmas = config.pragmas, hasConfig = config.has,
28392 //Legacy arg defined to help in dojo conversion script. Remove later
28393 //when dojo no longer needs conversion:
28394 kwArgs = pragmas;
28395
28396 //Mix in a specific lifecycle scoped object, to allow targeting
28397 //some pragmas/has tests to only when files are saved, or at different
28398 //lifecycle events. Do not bother with kwArgs in this section, since
28399 //the old dojo kwArgs were for all points in the build lifecycle.
28400 if (onLifecycleName) {
28401 lifecyclePragmas = config['pragmas' + onLifecycleName];
28402 lifecycleHas = config['has' + onLifecycleName];
28403
28404 if (lifecyclePragmas) {
28405 pragmas = create(pragmas || {}, lifecyclePragmas);
28406 }
28407
28408 if (lifecycleHas) {
28409 hasConfig = create(hasConfig || {}, lifecycleHas);
28410 }
28411 }
28412
28413 //Replace has references if desired
28414 if (hasConfig) {
28415 fileContents = fileContents.replace(pragma.hasRegExp, function (match, test) {
28416 if (hasConfig.hasOwnProperty(test)) {
28417 return !!hasConfig[test];
28418 }
28419 return match;
28420 });
28421 }
28422
28423 if (!config.skipPragmas) {
28424
28425 while ((foundIndex = fileContents.indexOf("//>>", startIndex)) !== -1) {
28426 //Found a conditional. Get the conditional line.
28427 lineEndIndex = fileContents.indexOf("\n", foundIndex);
28428 if (lineEndIndex === -1) {
28429 lineEndIndex = fileContents.length - 1;
28430 }
28431
28432 //Increment startIndex past the line so the next conditional search can be done.
28433 startIndex = lineEndIndex + 1;
28434
28435 //Break apart the conditional.
28436 conditionLine = fileContents.substring(foundIndex, lineEndIndex + 1);
28437 matches = conditionLine.match(pragma.conditionalRegExp);
28438 if (matches) {
28439 type = matches[1];
28440 marker = matches[2];
28441 condition = matches[3];
28442 isTrue = false;
28443 //See if the condition is true.
28444 try {
28445 isTrue = !!eval("(" + condition + ")");
28446 } catch (e) {
28447 throw "Error in file: " +
28448 fileName +
28449 ". Conditional comment: " +
28450 conditionLine +
28451 " failed with this error: " + e;
28452 }
28453
28454 //Find the endpoint marker.
28455 endRegExp = new RegExp('\\/\\/\\>\\>\\s*' + type + 'End\\(\\s*[\'"]' + marker + '[\'"]\\s*\\)', "g");
28456 endMatches = endRegExp.exec(fileContents.substring(startIndex, fileContents.length));
28457 if (endMatches) {
28458 endMarkerIndex = startIndex + endRegExp.lastIndex - endMatches[0].length;
28459
28460 //Find the next line return based on the match position.
28461 lineEndIndex = fileContents.indexOf("\n", endMarkerIndex);
28462 if (lineEndIndex === -1) {
28463 lineEndIndex = fileContents.length - 1;
28464 }
28465
28466 //Should we include the segment?
28467 shouldInclude = ((type === "exclude" && !isTrue) || (type === "include" && isTrue));
28468
28469 //Remove the conditional comments, and optionally remove the content inside
28470 //the conditional comments.
28471 startLength = startIndex - foundIndex;
28472 fileContents = fileContents.substring(0, foundIndex) +
28473 (shouldInclude ? fileContents.substring(startIndex, endMarkerIndex) : "") +
28474 fileContents.substring(lineEndIndex + 1, fileContents.length);
28475
28476 //Move startIndex to foundIndex, since that is the new position in the file
28477 //where we need to look for more conditionals in the next while loop pass.
28478 startIndex = foundIndex;
28479 } else {
28480 throw "Error in file: " +
28481 fileName +
28482 ". Cannot find end marker for conditional comment: " +
28483 conditionLine;
28484
28485 }
28486 }
28487 }
28488 }
28489
28490 //If need to find all plugin resources to optimize, do that now,
28491 //before namespacing, since the namespacing will change the API
28492 //names.
28493 //If there is a plugin collector, scan the file for plugin resources.
28494 if (config.optimizeAllPluginResources && pluginCollector) {
28495 try {
28496 deps = parse.findDependencies(fileName, fileContents);
28497 if (deps.length) {
28498 for (i = 0; i < deps.length; i++) {
28499 dep = deps[i];
28500 if (dep.indexOf('!') !== -1) {
28501 moduleName = dep.split('!')[0];
28502 collectorMod = pluginCollector[moduleName];
28503 if (!collectorMod) {
28504 collectorMod = pluginCollector[moduleName] = [];
28505 }
28506 collectorMod.push(dep);
28507 }
28508 }
28509 }
28510 } catch (eDep) {
28511 logger.error('Parse error looking for plugin resources in ' +
28512 fileName + ', skipping.');
28513 }
28514 }
28515
28516 //Strip amdefine use for node-shared modules.
28517 if (!config.keepAmdefine) {
28518 fileContents = fileContents.replace(pragma.amdefineRegExp, '');
28519 }
28520
28521 //Do namespacing
28522 if (onLifecycleName === 'OnSave' && config.namespace) {
28523 fileContents = pragma.namespace(fileContents, config.namespace, onLifecycleName);
28524 }
28525
28526
28527 return pragma.removeStrict(fileContents, config);
28528 }
28529 };
28530
28531 return pragma;
28532});
28533
28534if(env === 'browser') {
28535/**
28536 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
28537 * Available via the MIT or new BSD license.
28538 * see: http://github.com/jrburke/requirejs for details
28539 */
28540
28541/*jslint strict: false */
28542/*global define: false */
28543
28544define('browser/optimize', {});
28545
28546}
28547
28548if(env === 'node') {
28549/**
28550 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
28551 * Available via the MIT or new BSD license.
28552 * see: http://github.com/jrburke/requirejs for details
28553 */
28554
28555/*jslint strict: false */
28556/*global define: false */
28557
28558define('node/optimize', {});
28559
28560}
28561
28562if(env === 'rhino') {
28563/**
28564 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
28565 * Available via the MIT or new BSD license.
28566 * see: http://github.com/jrburke/requirejs for details
28567 */
28568
28569/*jslint sloppy: true, plusplus: true */
28570/*global define, java, Packages, com */
28571
28572define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) {
28573
28574 //Add .reduce to Rhino so UglifyJS can run in Rhino,
28575 //inspired by https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
28576 //but rewritten for brevity, and to be good enough for use by UglifyJS.
28577 if (!Array.prototype.reduce) {
28578 Array.prototype.reduce = function (fn /*, initialValue */) {
28579 var i = 0,
28580 length = this.length,
28581 accumulator;
28582
28583 if (arguments.length >= 2) {
28584 accumulator = arguments[1];
28585 } else {
28586 if (length) {
28587 while (!(i in this)) {
28588 i++;
28589 }
28590 accumulator = this[i++];
28591 }
28592 }
28593
28594 for (; i < length; i++) {
28595 if (i in this) {
28596 accumulator = fn.call(undefined, accumulator, this[i], i, this);
28597 }
28598 }
28599
28600 return accumulator;
28601 };
28602 }
28603
28604 var JSSourceFilefromCode, optimize,
28605 mapRegExp = /"file":"[^"]+"/;
28606
28607 //Bind to Closure compiler, but if it is not available, do not sweat it.
28608 try {
28609 // Try older closure compiler that worked on Java 6
28610 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.JSSourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]);
28611 } catch (e) {
28612 try {
28613 // Try for newer closure compiler that needs Java 7+
28614 JSSourceFilefromCode = java.lang.Class.forName('com.google.javascript.jscomp.SourceFile').getMethod('fromCode', [java.lang.String, java.lang.String]);
28615 } catch (e) {
28616 try {
28617 // Try Nashorn style
28618 var stringClass = Java.type("java.lang.String").class;
28619 JSSourceFilefromCode = Java.type("com.google.javascript.jscomp.SourceFile").class.getMethod("fromCode", [stringClass, stringClass]);
28620 } catch (e) {}
28621 }
28622 }
28623
28624 //Helper for closure compiler, because of weird Java-JavaScript interactions.
28625 function closurefromCode(filename, content) {
28626 return JSSourceFilefromCode.invoke(null, [filename, content]);
28627 }
28628
28629
28630 function getFileWriter(fileName, encoding) {
28631 var outFile = new java.io.File(fileName), outWriter, parentDir;
28632
28633 parentDir = outFile.getAbsoluteFile().getParentFile();
28634 if (!parentDir.exists()) {
28635 if (!parentDir.mkdirs()) {
28636 throw "Could not create directory: " + parentDir.getAbsolutePath();
28637 }
28638 }
28639
28640 if (encoding) {
28641 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile), encoding);
28642 } else {
28643 outWriter = new java.io.OutputStreamWriter(new java.io.FileOutputStream(outFile));
28644 }
28645
28646 return new java.io.BufferedWriter(outWriter);
28647 }
28648
28649 optimize = {
28650 closure: function (fileName, fileContents, outFileName, keepLines, config) {
28651 config = config || {};
28652 var result, mappings, optimized, compressed, baseName, writer,
28653 outBaseName, outFileNameMap, outFileNameMapContent,
28654 srcOutFileName, concatNameMap,
28655 jscomp = Packages.com.google.javascript.jscomp,
28656 flags = Packages.com.google.common.flags,
28657 //Set up source input
28658 jsSourceFile = closurefromCode(String(fileName), String(fileContents)),
28659 sourceListArray = new java.util.ArrayList(),
28660 externList = new java.util.ArrayList(),
28661 options, option, FLAG_compilation_level, compiler, externExportsPath,
28662 Compiler = Packages.com.google.javascript.jscomp.Compiler,
28663 CommandLineRunner = Packages.com.google.javascript.jscomp.CommandLineRunner;
28664
28665 logger.trace("Minifying file: " + fileName);
28666
28667 baseName = (new java.io.File(fileName)).getName();
28668
28669 //Set up options
28670 options = new jscomp.CompilerOptions();
28671 for (option in config.CompilerOptions) {
28672 // options are false by default and jslint wanted an if statement in this for loop
28673 if (config.CompilerOptions[option]) {
28674 options[option] = config.CompilerOptions[option];
28675 }
28676
28677 }
28678 options.prettyPrint = keepLines || options.prettyPrint;
28679
28680 FLAG_compilation_level = jscomp.CompilationLevel[config.CompilationLevel || 'SIMPLE_OPTIMIZATIONS'];
28681 FLAG_compilation_level.setOptionsForCompilationLevel(options);
28682
28683 if (config.generateSourceMaps) {
28684 mappings = new java.util.ArrayList();
28685
28686 mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src.js"));
28687 options.setSourceMapLocationMappings(mappings);
28688 options.setSourceMapOutputPath(fileName + ".map");
28689 }
28690
28691 //If we need to pass an externs file to Closure so that it does not create aliases
28692 //for certain symbols, do so here.
28693 externList.addAll(CommandLineRunner.getDefaultExterns());
28694 if (config.externExportsPath) {
28695 externExportsPath = config.externExportsPath;
28696 externList.add(jscomp.SourceFile.fromFile(externExportsPath));
28697 }
28698
28699 //Trigger the compiler
28700 Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']);
28701 compiler = new Compiler();
28702
28703 //fill the sourceArrrayList; we need the ArrayList because the only overload of compile
28704 //accepting the getDefaultExterns return value (a List) also wants the sources as a List
28705 sourceListArray.add(jsSourceFile);
28706
28707 result = compiler.compile(externList, sourceListArray, options);
28708 if (result.success) {
28709 optimized = String(compiler.toSource());
28710
28711 if (config.generateSourceMaps && result.sourceMap && outFileName) {
28712 outBaseName = (new java.io.File(outFileName)).getName();
28713
28714 srcOutFileName = outFileName + ".src.js";
28715 outFileNameMap = outFileName + ".map";
28716
28717 //If previous .map file exists, move it to the ".src.js"
28718 //location. Need to update the sourceMappingURL part in the
28719 //src.js file too.
28720 if (file.exists(outFileNameMap)) {
28721 concatNameMap = outFileNameMap.replace(/\.map$/, '.src.js.map');
28722 file.saveFile(concatNameMap, file.readFile(outFileNameMap));
28723 file.saveFile(srcOutFileName,
28724 fileContents.replace(/\/\# sourceMappingURL=(.+).map/,
28725 '/# sourceMappingURL=$1.src.js.map'));
28726 } else {
28727 file.saveUtf8File(srcOutFileName, fileContents);
28728 }
28729
28730 writer = getFileWriter(outFileNameMap, "utf-8");
28731 result.sourceMap.appendTo(writer, outFileName);
28732 writer.close();
28733
28734 //Not sure how better to do this, but right now the .map file
28735 //leaks the full OS path in the "file" property. Manually
28736 //modify it to not do that.
28737 file.saveFile(outFileNameMap,
28738 file.readFile(outFileNameMap).replace(mapRegExp, '"file":"' + baseName + '"'));
28739
28740 fileContents = optimized + "\n//# sourceMappingURL=" + outBaseName + ".map";
28741 } else {
28742 fileContents = optimized;
28743 }
28744 return fileContents;
28745 } else {
28746 throw new Error('Cannot closure compile file: ' + fileName + '. Skipping it.');
28747 }
28748
28749 return fileContents;
28750 }
28751 };
28752
28753 return optimize;
28754});
28755}
28756
28757if(env === 'xpconnect') {
28758define('xpconnect/optimize', {});
28759}
28760/**
28761 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
28762 * Available via the MIT or new BSD license.
28763 * see: http://github.com/jrburke/requirejs for details
28764 */
28765
28766/*jslint plusplus: true, nomen: true, regexp: true */
28767/*global define: false */
28768
28769define('optimize', [ 'lang', 'logger', 'env!env/optimize', 'env!env/file', 'parse',
28770 'pragma', 'uglifyjs/index', 'uglifyjs2',
28771 'source-map'],
28772function (lang, logger, envOptimize, file, parse,
28773 pragma, uglify, uglify2,
28774 sourceMap) {
28775 'use strict';
28776
28777 var optimize,
28778 cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig,
28779 cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g,
28780 cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g,
28781 protocolRegExp = /^\w+:/,
28782 SourceMapGenerator = sourceMap.SourceMapGenerator,
28783 SourceMapConsumer =sourceMap.SourceMapConsumer;
28784
28785 /**
28786 * If an URL from a CSS url value contains start/end quotes, remove them.
28787 * This is not done in the regexp, since my regexp fu is not that strong,
28788 * and the CSS spec allows for ' and " in the URL if they are backslash escaped.
28789 * @param {String} url
28790 */
28791 function cleanCssUrlQuotes(url) {
28792 //Make sure we are not ending in whitespace.
28793 //Not very confident of the css regexps above that there will not be ending
28794 //whitespace.
28795 url = url.replace(/\s+$/, "");
28796
28797 if (url.charAt(0) === "'" || url.charAt(0) === "\"") {
28798 url = url.substring(1, url.length - 1);
28799 }
28800
28801 return url;
28802 }
28803
28804 function fixCssUrlPaths(fileName, path, contents, cssPrefix) {
28805 return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) {
28806 var firstChar, hasProtocol, parts, i,
28807 fixedUrlMatch = cleanCssUrlQuotes(urlMatch);
28808
28809 fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/");
28810
28811 //Only do the work for relative URLs. Skip things that start with / or #, or have
28812 //a protocol.
28813 firstChar = fixedUrlMatch.charAt(0);
28814 hasProtocol = protocolRegExp.test(fixedUrlMatch);
28815 if (firstChar !== "/" && firstChar !== "#" && !hasProtocol) {
28816 //It is a relative URL, tack on the cssPrefix and path prefix
28817 urlMatch = cssPrefix + path + fixedUrlMatch;
28818 } else if (!hasProtocol) {
28819 logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch);
28820 }
28821
28822 //Collapse .. and .
28823 parts = urlMatch.split("/");
28824 for (i = parts.length - 1; i > 0; i--) {
28825 if (parts[i] === ".") {
28826 parts.splice(i, 1);
28827 } else if (parts[i] === "..") {
28828 if (i !== 0 && parts[i - 1] !== "..") {
28829 parts.splice(i - 1, 2);
28830 i -= 1;
28831 }
28832 }
28833 }
28834
28835 return "url(" + parts.join("/") + ")";
28836 });
28837 }
28838
28839 /**
28840 * Inlines nested stylesheets that have @import calls in them.
28841 * @param {String} fileName the file name
28842 * @param {String} fileContents the file contents
28843 * @param {String} cssImportIgnore comma delimited string of files to ignore
28844 * @param {String} cssPrefix string to be prefixed before relative URLs
28845 * @param {Object} included an object used to track the files already imported
28846 */
28847 function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included, topLevel) {
28848 //Find the last slash in the name.
28849 fileName = fileName.replace(lang.backSlashRegExp, "/");
28850 var endIndex = fileName.lastIndexOf("/"),
28851 //Make a file path based on the last slash.
28852 //If no slash, so must be just a file name. Use empty string then.
28853 filePath = (endIndex !== -1) ? fileName.substring(0, endIndex + 1) : "",
28854 //store a list of merged files
28855 importList = [],
28856 skippedList = [];
28857
28858 //First make a pass by removing any commented out @import calls.
28859 fileContents = fileContents.replace(cssCommentImportRegExp, '');
28860
28861 //Make sure we have a delimited ignore list to make matching faster
28862 if (cssImportIgnore && cssImportIgnore.charAt(cssImportIgnore.length - 1) !== ",") {
28863 cssImportIgnore += ",";
28864 }
28865
28866 fileContents = fileContents.replace(cssImportRegExp, function (fullMatch, urlStart, importFileName, urlEnd, mediaTypes) {
28867 //Only process media type "all" or empty media type rules.
28868 if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) {
28869 skippedList.push(fileName);
28870 return fullMatch;
28871 }
28872
28873 importFileName = cleanCssUrlQuotes(importFileName);
28874
28875 //Ignore the file import if it is part of an ignore list.
28876 if (cssImportIgnore && cssImportIgnore.indexOf(importFileName + ",") !== -1) {
28877 return fullMatch;
28878 }
28879
28880 //Make sure we have a unix path for the rest of the operation.
28881 importFileName = importFileName.replace(lang.backSlashRegExp, "/");
28882
28883 try {
28884 //if a relative path, then tack on the filePath.
28885 //If it is not a relative path, then the readFile below will fail,
28886 //and we will just skip that import.
28887 var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName,
28888 importContents = file.readFile(fullImportFileName),
28889 importEndIndex, importPath, flat;
28890
28891 //Skip the file if it has already been included.
28892 if (included[fullImportFileName]) {
28893 return '';
28894 }
28895 included[fullImportFileName] = true;
28896
28897 //Make sure to flatten any nested imports.
28898 flat = flattenCss(fullImportFileName, importContents, cssImportIgnore, cssPrefix, included);
28899 importContents = flat.fileContents;
28900
28901 if (flat.importList.length) {
28902 importList.push.apply(importList, flat.importList);
28903 }
28904 if (flat.skippedList.length) {
28905 skippedList.push.apply(skippedList, flat.skippedList);
28906 }
28907
28908 //Make the full import path
28909 importEndIndex = importFileName.lastIndexOf("/");
28910
28911 //Make a file path based on the last slash.
28912 //If no slash, so must be just a file name. Use empty string then.
28913 importPath = (importEndIndex !== -1) ? importFileName.substring(0, importEndIndex + 1) : "";
28914
28915 //fix url() on relative import (#5)
28916 importPath = importPath.replace(/^\.\//, '');
28917
28918 //Modify URL paths to match the path represented by this file.
28919 importContents = fixCssUrlPaths(importFileName, importPath, importContents, cssPrefix);
28920
28921 importList.push(fullImportFileName);
28922 return importContents;
28923 } catch (e) {
28924 logger.warn(fileName + "\n Cannot inline css import, skipping: " + importFileName);
28925 return fullMatch;
28926 }
28927 });
28928
28929 if (cssPrefix && topLevel) {
28930 //Modify URL paths to match the path represented by this file.
28931 fileContents = fixCssUrlPaths(fileName, '', fileContents, cssPrefix);
28932 }
28933
28934 return {
28935 importList : importList,
28936 skippedList: skippedList,
28937 fileContents : fileContents
28938 };
28939 }
28940
28941 optimize = {
28942 /**
28943 * Optimizes a file that contains JavaScript content. Optionally collects
28944 * plugin resources mentioned in a file, and then passes the content
28945 * through an minifier if one is specified via config.optimize.
28946 *
28947 * @param {String} fileName the name of the file to optimize
28948 * @param {String} fileContents the contents to optimize. If this is
28949 * a null value, then fileName will be used to read the fileContents.
28950 * @param {String} outFileName the name of the file to use for the
28951 * saved optimized content.
28952 * @param {Object} config the build config object.
28953 * @param {Array} [pluginCollector] storage for any plugin resources
28954 * found.
28955 */
28956 jsFile: function (fileName, fileContents, outFileName, config, pluginCollector) {
28957 if (!fileContents) {
28958 fileContents = file.readFile(fileName);
28959 }
28960
28961 fileContents = optimize.js(fileName, fileContents, outFileName, config, pluginCollector);
28962
28963 file.saveUtf8File(outFileName, fileContents);
28964 },
28965
28966 /**
28967 * Optimizes a file that contains JavaScript content. Optionally collects
28968 * plugin resources mentioned in a file, and then passes the content
28969 * through an minifier if one is specified via config.optimize.
28970 *
28971 * @param {String} fileName the name of the file that matches the
28972 * fileContents.
28973 * @param {String} fileContents the string of JS to optimize.
28974 * @param {Object} [config] the build config object.
28975 * @param {Array} [pluginCollector] storage for any plugin resources
28976 * found.
28977 */
28978 js: function (fileName, fileContents, outFileName, config, pluginCollector) {
28979 var optFunc, optConfig,
28980 parts = (String(config.optimize)).split('.'),
28981 optimizerName = parts[0],
28982 keepLines = parts[1] === 'keepLines',
28983 licenseContents = '';
28984
28985 config = config || {};
28986
28987 //Apply pragmas/namespace renaming
28988 fileContents = pragma.process(fileName, fileContents, config, 'OnSave', pluginCollector);
28989
28990 //Optimize the JS files if asked.
28991 if (optimizerName && optimizerName !== 'none') {
28992 optFunc = envOptimize[optimizerName] || optimize.optimizers[optimizerName];
28993 if (!optFunc) {
28994 throw new Error('optimizer with name of "' +
28995 optimizerName +
28996 '" not found for this environment');
28997 }
28998
28999 optConfig = config[optimizerName] || {};
29000 if (config.generateSourceMaps) {
29001 optConfig.generateSourceMaps = !!config.generateSourceMaps;
29002 optConfig._buildSourceMap = config._buildSourceMap;
29003 }
29004
29005 try {
29006 if (config.preserveLicenseComments) {
29007 //Pull out any license comments for prepending after optimization.
29008 try {
29009 licenseContents = parse.getLicenseComments(fileName, fileContents);
29010 } catch (e) {
29011 throw new Error('Cannot parse file: ' + fileName + ' for comments. Skipping it. Error is:\n' + e.toString());
29012 }
29013 }
29014
29015 fileContents = licenseContents + optFunc(fileName,
29016 fileContents,
29017 outFileName,
29018 keepLines,
29019 optConfig);
29020 if (optConfig._buildSourceMap && optConfig._buildSourceMap !== config._buildSourceMap) {
29021 config._buildSourceMap = optConfig._buildSourceMap;
29022 }
29023 } catch (e) {
29024 if (config.throwWhen && config.throwWhen.optimize) {
29025 throw e;
29026 } else {
29027 logger.error(e);
29028 }
29029 }
29030 } else {
29031 if (config._buildSourceMap) {
29032 config._buildSourceMap = null;
29033 }
29034 }
29035
29036 return fileContents;
29037 },
29038
29039 /**
29040 * Optimizes one CSS file, inlining @import calls, stripping comments, and
29041 * optionally removes line returns.
29042 * @param {String} fileName the path to the CSS file to optimize
29043 * @param {String} outFileName the path to save the optimized file.
29044 * @param {Object} config the config object with the optimizeCss and
29045 * cssImportIgnore options.
29046 */
29047 cssFile: function (fileName, outFileName, config) {
29048
29049 //Read in the file. Make sure we have a JS string.
29050 var originalFileContents = file.readFile(fileName),
29051 flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}, true),
29052 //Do not use the flattened CSS if there was one that was skipped.
29053 fileContents = flat.skippedList.length ? originalFileContents : flat.fileContents,
29054 startIndex, endIndex, buildText, comment;
29055
29056 if (flat.skippedList.length) {
29057 logger.warn('Cannot inline @imports for ' + fileName +
29058 ',\nthe following files had media queries in them:\n' +
29059 flat.skippedList.join('\n'));
29060 }
29061
29062 //Do comment removal.
29063 try {
29064 if (config.optimizeCss.indexOf(".keepComments") === -1) {
29065 startIndex = 0;
29066 //Get rid of comments.
29067 while ((startIndex = fileContents.indexOf("/*", startIndex)) !== -1) {
29068 endIndex = fileContents.indexOf("*/", startIndex + 2);
29069 if (endIndex === -1) {
29070 throw "Improper comment in CSS file: " + fileName;
29071 }
29072 comment = fileContents.substring(startIndex, endIndex);
29073
29074 if (config.preserveLicenseComments &&
29075 (comment.indexOf('license') !== -1 ||
29076 comment.indexOf('opyright') !== -1 ||
29077 comment.indexOf('(c)') !== -1)) {
29078 //Keep the comment, just increment the startIndex
29079 startIndex = endIndex;
29080 } else {
29081 fileContents = fileContents.substring(0, startIndex) + fileContents.substring(endIndex + 2, fileContents.length);
29082 startIndex = 0;
29083 }
29084 }
29085 }
29086 //Get rid of newlines.
29087 if (config.optimizeCss.indexOf(".keepLines") === -1) {
29088 fileContents = fileContents.replace(/[\r\n]/g, " ");
29089 fileContents = fileContents.replace(/\s+/g, " ");
29090 fileContents = fileContents.replace(/\{\s/g, "{");
29091 fileContents = fileContents.replace(/\s\}/g, "}");
29092 } else {
29093 //Remove multiple empty lines.
29094 fileContents = fileContents.replace(/(\r\n)+/g, "\r\n");
29095 fileContents = fileContents.replace(/(\n)+/g, "\n");
29096 }
29097 //Remove unnecessary whitespace
29098 if (config.optimizeCss.indexOf(".keepWhitespace") === -1) {
29099 //Remove leading and trailing whitespace from lines
29100 fileContents = fileContents.replace(/^[ \t]+/gm, "");
29101 fileContents = fileContents.replace(/[ \t]+$/gm, "");
29102 //Remove whitespace after semicolon, colon, curly brackets and commas
29103 fileContents = fileContents.replace(/(;|:|\{|}|,)[ \t]+/g, "$1");
29104 //Remove whitespace before opening curly brackets
29105 fileContents = fileContents.replace(/[ \t]+(\{)/g, "$1");
29106 //Truncate double whitespace
29107 fileContents = fileContents.replace(/([ \t])+/g, "$1");
29108 //Remove empty lines
29109 fileContents = fileContents.replace(/^[ \t]*[\r\n]/gm,'');
29110 }
29111 } catch (e) {
29112 fileContents = originalFileContents;
29113 logger.error("Could not optimized CSS file: " + fileName + ", error: " + e);
29114 }
29115
29116 file.saveUtf8File(outFileName, fileContents);
29117
29118 //text output to stdout and/or written to build.txt file
29119 buildText = "\n"+ outFileName.replace(config.dir, "") +"\n----------------\n";
29120 flat.importList.push(fileName);
29121 buildText += flat.importList.map(function(path){
29122 return path.replace(config.dir, "");
29123 }).join("\n");
29124
29125 return {
29126 importList: flat.importList,
29127 buildText: buildText +"\n"
29128 };
29129 },
29130
29131 /**
29132 * Optimizes CSS files, inlining @import calls, stripping comments, and
29133 * optionally removes line returns.
29134 * @param {String} startDir the path to the top level directory
29135 * @param {Object} config the config object with the optimizeCss and
29136 * cssImportIgnore options.
29137 */
29138 css: function (startDir, config) {
29139 var buildText = "",
29140 importList = [],
29141 shouldRemove = config.dir && config.removeCombined,
29142 i, fileName, result, fileList;
29143 if (config.optimizeCss.indexOf("standard") !== -1) {
29144 fileList = file.getFilteredFileList(startDir, /\.css$/, true);
29145 if (fileList) {
29146 for (i = 0; i < fileList.length; i++) {
29147 fileName = fileList[i];
29148 logger.trace("Optimizing (" + config.optimizeCss + ") CSS file: " + fileName);
29149 result = optimize.cssFile(fileName, fileName, config);
29150 buildText += result.buildText;
29151 if (shouldRemove) {
29152 result.importList.pop();
29153 importList = importList.concat(result.importList);
29154 }
29155 }
29156 }
29157
29158 if (shouldRemove) {
29159 importList.forEach(function (path) {
29160 if (file.exists(path)) {
29161 file.deleteFile(path);
29162 }
29163 });
29164 }
29165 }
29166 return buildText;
29167 },
29168
29169 optimizers: {
29170 uglify: function (fileName, fileContents, outFileName, keepLines, config) {
29171 var parser = uglify.parser,
29172 processor = uglify.uglify,
29173 ast, errMessage, errMatch;
29174
29175 config = config || {};
29176
29177 logger.trace("Uglifying file: " + fileName);
29178
29179 try {
29180 ast = parser.parse(fileContents, config.strict_semicolons);
29181 if (config.no_mangle !== true) {
29182 ast = processor.ast_mangle(ast, config);
29183 }
29184 ast = processor.ast_squeeze(ast, config);
29185
29186 fileContents = processor.gen_code(ast, config);
29187
29188 if (config.max_line_length) {
29189 fileContents = processor.split_lines(fileContents, config.max_line_length);
29190 }
29191
29192 //Add trailing semicolon to match uglifyjs command line version
29193 fileContents += ';';
29194 } catch (e) {
29195 errMessage = e.toString();
29196 errMatch = /\nError(\r)?\n/.exec(errMessage);
29197 if (errMatch) {
29198 errMessage = errMessage.substring(0, errMatch.index);
29199 }
29200 throw new Error('Cannot uglify file: ' + fileName + '. Skipping it. Error is:\n' + errMessage);
29201 }
29202 return fileContents;
29203 },
29204 uglify2: function (fileName, fileContents, outFileName, keepLines, config) {
29205 var result, existingMap, resultMap, finalMap, sourceIndex,
29206 uconfig = {},
29207 existingMapPath = outFileName + '.map',
29208 baseName = fileName && fileName.split('/').pop();
29209
29210 config = config || {};
29211
29212 lang.mixin(uconfig, config, true);
29213
29214 uconfig.fromString = true;
29215
29216 if (config.generateSourceMaps && (outFileName || config._buildSourceMap)) {
29217 uconfig.outSourceMap = baseName + '.map';
29218
29219 if (config._buildSourceMap) {
29220 existingMap = JSON.parse(config._buildSourceMap);
29221 uconfig.inSourceMap = existingMap;
29222 } else if (file.exists(existingMapPath)) {
29223 uconfig.inSourceMap = existingMapPath;
29224 existingMap = JSON.parse(file.readFile(existingMapPath));
29225 }
29226 }
29227
29228 logger.trace("Uglify2 file: " + fileName);
29229
29230 try {
29231 //var tempContents = fileContents.replace(/\/\/\# sourceMappingURL=.*$/, '');
29232 result = uglify2.minify(fileContents, uconfig, baseName + '.src.js');
29233 if (uconfig.outSourceMap && result.map) {
29234 resultMap = result.map;
29235 if (!existingMap && !config._buildSourceMap) {
29236 file.saveFile(outFileName + '.src.js', fileContents);
29237 }
29238
29239 fileContents = result.code;
29240
29241 if (config._buildSourceMap) {
29242 config._buildSourceMap = resultMap;
29243 } else {
29244 file.saveFile(outFileName + '.map', resultMap);
29245 }
29246 } else {
29247 fileContents = result.code;
29248 }
29249 } catch (e) {
29250 throw new Error('Cannot uglify2 file: ' + fileName + '. Skipping it. Error is:\n' + e.toString());
29251 }
29252 return fileContents;
29253 }
29254 }
29255 };
29256
29257 return optimize;
29258});
29259/**
29260 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
29261 * Available via the MIT or new BSD license.
29262 * see: http://github.com/jrburke/requirejs for details
29263 */
29264/*
29265 * This file patches require.js to communicate with the build system.
29266 */
29267
29268//Using sloppy since this uses eval for some code like plugins,
29269//which may not be strict mode compliant. So if use strict is used
29270//below they will have strict rules applied and may cause an error.
29271/*jslint sloppy: true, nomen: true, plusplus: true, regexp: true */
29272/*global require, define: true */
29273
29274//NOT asking for require as a dependency since the goal is to modify the
29275//global require below
29276define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim'], function (
29277 file,
29278 pragma,
29279 parse,
29280 lang,
29281 logger,
29282 commonJs,
29283 prim
29284) {
29285
29286 var allowRun = true,
29287 hasProp = lang.hasProp,
29288 falseProp = lang.falseProp,
29289 getOwn = lang.getOwn,
29290 // Used to strip out use strict from toString()'d functions for the
29291 // shim config since they will explicitly want to not be bound by strict,
29292 // but some envs, explicitly xpcshell, adds a use strict.
29293 useStrictRegExp = /['"]use strict['"];/g;
29294
29295 //Turn off throwing on resolution conflict, that was just an older prim
29296 //idea about finding errors early, but does not comply with how promises
29297 //should operate.
29298 prim.hideResolutionConflict = true;
29299
29300 //This method should be called when the patches to require should take hold.
29301 return function () {
29302 if (!allowRun) {
29303 return;
29304 }
29305 allowRun = false;
29306
29307 var layer,
29308 pluginBuilderRegExp = /(["']?)pluginBuilder(["']?)\s*[=\:]\s*["']([^'"\s]+)["']/,
29309 oldNewContext = require.s.newContext,
29310 oldDef,
29311
29312 //create local undefined values for module and exports,
29313 //so that when files are evaled in this function they do not
29314 //see the node values used for r.js
29315 exports,
29316 module;
29317
29318 /**
29319 * Reset "global" build caches that are kept around between
29320 * build layer builds. Useful to do when there are multiple
29321 * top level requirejs.optimize() calls.
29322 */
29323 require._cacheReset = function () {
29324 //Stored raw text caches, used by browser use.
29325 require._cachedRawText = {};
29326 //Stored cached file contents for reuse in other layers.
29327 require._cachedFileContents = {};
29328 //Store which cached files contain a require definition.
29329 require._cachedDefinesRequireUrls = {};
29330 };
29331 require._cacheReset();
29332
29333 /**
29334 * Makes sure the URL is something that can be supported by the
29335 * optimization tool.
29336 * @param {String} url
29337 * @returns {Boolean}
29338 */
29339 require._isSupportedBuildUrl = function (url) {
29340 //Ignore URLs with protocols, hosts or question marks, means either network
29341 //access is needed to fetch it or it is too dynamic. Note that
29342 //on Windows, full paths are used for some urls, which include
29343 //the drive, like c:/something, so need to test for something other
29344 //than just a colon.
29345 if (url.indexOf("://") === -1 && url.indexOf("?") === -1 &&
29346 url.indexOf('empty:') !== 0 && url.indexOf('//') !== 0) {
29347 return true;
29348 } else {
29349 if (!layer.ignoredUrls[url]) {
29350 if (url.indexOf('empty:') === -1) {
29351 logger.info('Cannot optimize network URL, skipping: ' + url);
29352 }
29353 layer.ignoredUrls[url] = true;
29354 }
29355 return false;
29356 }
29357 };
29358
29359 function normalizeUrlWithBase(context, moduleName, url) {
29360 //Adjust the URL if it was not transformed to use baseUrl.
29361 if (require.jsExtRegExp.test(moduleName)) {
29362 url = (context.config.dir || context.config.dirBaseUrl) + url;
29363 }
29364 return url;
29365 }
29366
29367 //Overrides the new context call to add existing tracking features.
29368 require.s.newContext = function (name) {
29369 var context = oldNewContext(name),
29370 oldEnable = context.enable,
29371 moduleProto = context.Module.prototype,
29372 oldInit = moduleProto.init,
29373 oldCallPlugin = moduleProto.callPlugin;
29374
29375 //Only do this for the context used for building.
29376 if (name === '_') {
29377 //For build contexts, do everything sync
29378 context.nextTick = function (fn) {
29379 fn();
29380 };
29381
29382 context.needFullExec = {};
29383 context.fullExec = {};
29384 context.plugins = {};
29385 context.buildShimExports = {};
29386
29387 //Override the shim exports function generator to just
29388 //spit out strings that can be used in the stringified
29389 //build output.
29390 context.makeShimExports = function (value) {
29391 var fn;
29392 if (context.config.wrapShim) {
29393 fn = function () {
29394 var str = 'return ';
29395 // If specifies an export that is just a global
29396 // name, no dot for a `this.` and such, then also
29397 // attach to the global, for `var a = {}` files
29398 // where the function closure would hide that from
29399 // the global object.
29400 if (value.exports && value.exports.indexOf('.') === -1) {
29401 str += 'root.' + value.exports + ' = ';
29402 }
29403
29404 if (value.init) {
29405 str += '(' + value.init.toString()
29406 .replace(useStrictRegExp, '') + '.apply(this, arguments))';
29407 }
29408 if (value.init && value.exports) {
29409 str += ' || ';
29410 }
29411 if (value.exports) {
29412 str += value.exports;
29413 }
29414 str += ';';
29415 return str;
29416 };
29417 } else {
29418 fn = function () {
29419 return '(function (global) {\n' +
29420 ' return function () {\n' +
29421 ' var ret, fn;\n' +
29422 (value.init ?
29423 (' fn = ' + value.init.toString()
29424 .replace(useStrictRegExp, '') + ';\n' +
29425 ' ret = fn.apply(global, arguments);\n') : '') +
29426 (value.exports ?
29427 ' return ret || global.' + value.exports + ';\n' :
29428 ' return ret;\n') +
29429 ' };\n' +
29430 '}(this))';
29431 };
29432 }
29433
29434 return fn;
29435 };
29436
29437 context.enable = function (depMap, parent) {
29438 var id = depMap.id,
29439 parentId = parent && parent.map.id,
29440 needFullExec = context.needFullExec,
29441 fullExec = context.fullExec,
29442 mod = getOwn(context.registry, id);
29443
29444 if (mod && !mod.defined) {
29445 if (parentId && getOwn(needFullExec, parentId)) {
29446 needFullExec[id] = depMap;
29447 }
29448
29449 } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) ||
29450 (parentId && getOwn(needFullExec, parentId) &&
29451 falseProp(fullExec, id))) {
29452 context.require.undef(id);
29453 }
29454
29455 return oldEnable.apply(context, arguments);
29456 };
29457
29458 //Override load so that the file paths can be collected.
29459 context.load = function (moduleName, url) {
29460 /*jslint evil: true */
29461 var contents, pluginBuilderMatch, builderName,
29462 shim, shimExports;
29463
29464 //Do not mark the url as fetched if it is
29465 //not an empty: URL, used by the optimizer.
29466 //In that case we need to be sure to call
29467 //load() for each module that is mapped to
29468 //empty: so that dependencies are satisfied
29469 //correctly.
29470 if (url.indexOf('empty:') === 0) {
29471 delete context.urlFetched[url];
29472 }
29473
29474 //Only handle urls that can be inlined, so that means avoiding some
29475 //URLs like ones that require network access or may be too dynamic,
29476 //like JSONP
29477 if (require._isSupportedBuildUrl(url)) {
29478 //Adjust the URL if it was not transformed to use baseUrl.
29479 url = normalizeUrlWithBase(context, moduleName, url);
29480
29481 //Save the module name to path and path to module name mappings.
29482 layer.buildPathMap[moduleName] = url;
29483 layer.buildFileToModule[url] = moduleName;
29484
29485 if (hasProp(context.plugins, moduleName)) {
29486 //plugins need to have their source evaled as-is.
29487 context.needFullExec[moduleName] = true;
29488 }
29489
29490 prim().start(function () {
29491 if (hasProp(require._cachedFileContents, url) &&
29492 (falseProp(context.needFullExec, moduleName) ||
29493 getOwn(context.fullExec, moduleName))) {
29494 contents = require._cachedFileContents[url];
29495
29496 //If it defines require, mark it so it can be hoisted.
29497 //Done here and in the else below, before the
29498 //else block removes code from the contents.
29499 //Related to #263
29500 if (!layer.existingRequireUrl && require._cachedDefinesRequireUrls[url]) {
29501 layer.existingRequireUrl = url;
29502 }
29503 } else {
29504 //Load the file contents, process for conditionals, then
29505 //evaluate it.
29506 return require._cacheReadAsync(url).then(function (text) {
29507 contents = text;
29508
29509 if (context.config.cjsTranslate &&
29510 (!context.config.shim || !lang.hasProp(context.config.shim, moduleName))) {
29511 contents = commonJs.convert(url, contents);
29512 }
29513
29514 //If there is a read filter, run it now.
29515 if (context.config.onBuildRead) {
29516 contents = context.config.onBuildRead(moduleName, url, contents);
29517 }
29518
29519 contents = pragma.process(url, contents, context.config, 'OnExecute');
29520
29521 //Find out if the file contains a require() definition. Need to know
29522 //this so we can inject plugins right after it, but before they are needed,
29523 //and to make sure this file is first, so that define calls work.
29524 try {
29525 if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) {
29526 layer.existingRequireUrl = url;
29527 require._cachedDefinesRequireUrls[url] = true;
29528 }
29529 } catch (e1) {
29530 throw new Error('Parse error using esprima ' +
29531 'for file: ' + url + '\n' + e1);
29532 }
29533 }).then(function () {
29534 if (hasProp(context.plugins, moduleName)) {
29535 //This is a loader plugin, check to see if it has a build extension,
29536 //otherwise the plugin will act as the plugin builder too.
29537 pluginBuilderMatch = pluginBuilderRegExp.exec(contents);
29538 if (pluginBuilderMatch) {
29539 //Load the plugin builder for the plugin contents.
29540 builderName = context.makeModuleMap(pluginBuilderMatch[3],
29541 context.makeModuleMap(moduleName),
29542 null,
29543 true).id;
29544 return require._cacheReadAsync(context.nameToUrl(builderName));
29545 }
29546 }
29547 return contents;
29548 }).then(function (text) {
29549 contents = text;
29550
29551 //Parse out the require and define calls.
29552 //Do this even for plugins in case they have their own
29553 //dependencies that may be separate to how the pluginBuilder works.
29554 try {
29555 if (falseProp(context.needFullExec, moduleName)) {
29556 contents = parse(moduleName, url, contents, {
29557 insertNeedsDefine: true,
29558 has: context.config.has,
29559 findNestedDependencies: context.config.findNestedDependencies
29560 });
29561 }
29562 } catch (e2) {
29563 throw new Error('Parse error using esprima ' +
29564 'for file: ' + url + '\n' + e2);
29565 }
29566
29567 require._cachedFileContents[url] = contents;
29568 });
29569 }
29570 }).then(function () {
29571 if (contents) {
29572 eval(contents);
29573 }
29574
29575 try {
29576 //If have a string shim config, and this is
29577 //a fully executed module, try to see if
29578 //it created a variable in this eval scope
29579 if (getOwn(context.needFullExec, moduleName)) {
29580 shim = getOwn(context.config.shim, moduleName);
29581 if (shim && shim.exports) {
29582 shimExports = eval(shim.exports);
29583 if (typeof shimExports !== 'undefined') {
29584 context.buildShimExports[moduleName] = shimExports;
29585 }
29586 }
29587 }
29588
29589 //Need to close out completion of this module
29590 //so that listeners will get notified that it is available.
29591 context.completeLoad(moduleName);
29592 } catch (e) {
29593 //Track which module could not complete loading.
29594 if (!e.moduleTree) {
29595 e.moduleTree = [];
29596 }
29597 e.moduleTree.push(moduleName);
29598 throw e;
29599 }
29600 }).then(null, function (eOuter) {
29601
29602 if (!eOuter.fileName) {
29603 eOuter.fileName = url;
29604 }
29605 throw eOuter;
29606 }).end();
29607 } else {
29608 //With unsupported URLs still need to call completeLoad to
29609 //finish loading.
29610 context.completeLoad(moduleName);
29611 }
29612 };
29613
29614 //Marks module has having a name, and optionally executes the
29615 //callback, but only if it meets certain criteria.
29616 context.execCb = function (name, cb, args, exports) {
29617 var buildShimExports = getOwn(layer.context.buildShimExports, name);
29618
29619 if (buildShimExports) {
29620 return buildShimExports;
29621 } else if (cb.__requireJsBuild || getOwn(layer.context.needFullExec, name)) {
29622 return cb.apply(exports, args);
29623 }
29624 return undefined;
29625 };
29626
29627 moduleProto.init = function (depMaps) {
29628 if (context.needFullExec[this.map.id]) {
29629 lang.each(depMaps, lang.bind(this, function (depMap) {
29630 if (typeof depMap === 'string') {
29631 depMap = context.makeModuleMap(depMap,
29632 (this.map.isDefine ? this.map : this.map.parentMap));
29633 }
29634
29635 if (!context.fullExec[depMap.id]) {
29636 context.require.undef(depMap.id);
29637 }
29638 }));
29639 }
29640
29641 return oldInit.apply(this, arguments);
29642 };
29643
29644 moduleProto.callPlugin = function () {
29645 var map = this.map,
29646 pluginMap = context.makeModuleMap(map.prefix),
29647 pluginId = pluginMap.id,
29648 pluginMod = getOwn(context.registry, pluginId);
29649
29650 context.plugins[pluginId] = true;
29651 context.needFullExec[pluginId] = map;
29652
29653 //If the module is not waiting to finish being defined,
29654 //undef it and start over, to get full execution.
29655 if (falseProp(context.fullExec, pluginId) && (!pluginMod || pluginMod.defined)) {
29656 context.require.undef(pluginMap.id);
29657 }
29658
29659 return oldCallPlugin.apply(this, arguments);
29660 };
29661 }
29662
29663 return context;
29664 };
29665
29666 //Clear up the existing context so that the newContext modifications
29667 //above will be active.
29668 delete require.s.contexts._;
29669
29670 /** Reset state for each build layer pass. */
29671 require._buildReset = function () {
29672 var oldContext = require.s.contexts._;
29673
29674 //Clear up the existing context.
29675 delete require.s.contexts._;
29676
29677 //Set up new context, so the layer object can hold onto it.
29678 require({});
29679
29680 layer = require._layer = {
29681 buildPathMap: {},
29682 buildFileToModule: {},
29683 buildFilePaths: [],
29684 pathAdded: {},
29685 modulesWithNames: {},
29686 needsDefine: {},
29687 existingRequireUrl: "",
29688 ignoredUrls: {},
29689 context: require.s.contexts._
29690 };
29691
29692 //Return the previous context in case it is needed, like for
29693 //the basic config object.
29694 return oldContext;
29695 };
29696
29697 require._buildReset();
29698
29699 //Override define() to catch modules that just define an object, so that
29700 //a dummy define call is not put in the build file for them. They do
29701 //not end up getting defined via context.execCb, so we need to catch them
29702 //at the define call.
29703 oldDef = define;
29704
29705 //This function signature does not have to be exact, just match what we
29706 //are looking for.
29707 define = function (name) {
29708 if (typeof name === "string" && falseProp(layer.needsDefine, name)) {
29709 layer.modulesWithNames[name] = true;
29710 }
29711 return oldDef.apply(require, arguments);
29712 };
29713
29714 define.amd = oldDef.amd;
29715
29716 //Add some utilities for plugins
29717 require._readFile = file.readFile;
29718 require._fileExists = function (path) {
29719 return file.exists(path);
29720 };
29721
29722 //Called when execManager runs for a dependency. Used to figure out
29723 //what order of execution.
29724 require.onResourceLoad = function (context, map) {
29725 var id = map.id,
29726 url;
29727
29728 // Fix up any maps that need to be normalized as part of the fullExec
29729 // plumbing for plugins to participate in the build.
29730 if (context.plugins && lang.hasProp(context.plugins, id)) {
29731 lang.eachProp(context.needFullExec, function(value, prop) {
29732 // For plugin entries themselves, they do not have a map
29733 // value in needFullExec, just a "true" entry.
29734 if (value !== true && value.prefix === id && value.unnormalized) {
29735 var map = context.makeModuleMap(value.originalName, value.parentMap);
29736 context.needFullExec[map.id] = map;
29737 }
29738 });
29739 }
29740
29741 //If build needed a full execution, indicate it
29742 //has been done now. But only do it if the context is tracking
29743 //that. Only valid for the context used in a build, not for
29744 //other contexts being run, like for useLib, plain requirejs
29745 //use in node/rhino.
29746 if (context.needFullExec && getOwn(context.needFullExec, id)) {
29747 context.fullExec[id] = map;
29748 }
29749
29750 //A plugin.
29751 if (map.prefix) {
29752 if (falseProp(layer.pathAdded, id)) {
29753 layer.buildFilePaths.push(id);
29754 //For plugins the real path is not knowable, use the name
29755 //for both module to file and file to module mappings.
29756 layer.buildPathMap[id] = id;
29757 layer.buildFileToModule[id] = id;
29758 layer.modulesWithNames[id] = true;
29759 layer.pathAdded[id] = true;
29760 }
29761 } else if (map.url && require._isSupportedBuildUrl(map.url)) {
29762 //If the url has not been added to the layer yet, and it
29763 //is from an actual file that was loaded, add it now.
29764 url = normalizeUrlWithBase(context, id, map.url);
29765 if (!layer.pathAdded[url] && getOwn(layer.buildPathMap, id)) {
29766 //Remember the list of dependencies for this layer.
29767 layer.buildFilePaths.push(url);
29768 layer.pathAdded[url] = true;
29769 }
29770 }
29771 };
29772
29773 //Called by output of the parse() function, when a file does not
29774 //explicitly call define, probably just require, but the parse()
29775 //function normalizes on define() for dependency mapping and file
29776 //ordering works correctly.
29777 require.needsDefine = function (moduleName) {
29778 layer.needsDefine[moduleName] = true;
29779 };
29780 };
29781});
29782/**
29783 * @license RequireJS Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
29784 * Available via the MIT or new BSD license.
29785 * see: http://github.com/jrburke/requirejs for details
29786 */
29787
29788/*jslint */
29789/*global define: false, console: false */
29790
29791define('commonJs', ['env!env/file', 'parse'], function (file, parse) {
29792 'use strict';
29793 var commonJs = {
29794 //Set to false if you do not want this file to log. Useful in environments
29795 //like node where you want the work to happen without noise.
29796 useLog: true,
29797
29798 convertDir: function (commonJsPath, savePath) {
29799 var fileList, i,
29800 jsFileRegExp = /\.js$/,
29801 fileName, convertedFileName, fileContents;
29802
29803 //Get list of files to convert.
29804 fileList = file.getFilteredFileList(commonJsPath, /\w/, true);
29805
29806 //Normalize on front slashes and make sure the paths do not end in a slash.
29807 commonJsPath = commonJsPath.replace(/\\/g, "/");
29808 savePath = savePath.replace(/\\/g, "/");
29809 if (commonJsPath.charAt(commonJsPath.length - 1) === "/") {
29810 commonJsPath = commonJsPath.substring(0, commonJsPath.length - 1);
29811 }
29812 if (savePath.charAt(savePath.length - 1) === "/") {
29813 savePath = savePath.substring(0, savePath.length - 1);
29814 }
29815
29816 //Cycle through all the JS files and convert them.
29817 if (!fileList || !fileList.length) {
29818 if (commonJs.useLog) {
29819 if (commonJsPath === "convert") {
29820 //A request just to convert one file.
29821 console.log('\n\n' + commonJs.convert(savePath, file.readFile(savePath)));
29822 } else {
29823 console.log("No files to convert in directory: " + commonJsPath);
29824 }
29825 }
29826 } else {
29827 for (i = 0; i < fileList.length; i++) {
29828 fileName = fileList[i];
29829 convertedFileName = fileName.replace(commonJsPath, savePath);
29830
29831 //Handle JS files.
29832 if (jsFileRegExp.test(fileName)) {
29833 fileContents = file.readFile(fileName);
29834 fileContents = commonJs.convert(fileName, fileContents);
29835 file.saveUtf8File(convertedFileName, fileContents);
29836 } else {
29837 //Just copy the file over.
29838 file.copyFile(fileName, convertedFileName, true);
29839 }
29840 }
29841 }
29842 },
29843
29844 /**
29845 * Does the actual file conversion.
29846 *
29847 * @param {String} fileName the name of the file.
29848 *
29849 * @param {String} fileContents the contents of a file :)
29850 *
29851 * @returns {String} the converted contents
29852 */
29853 convert: function (fileName, fileContents) {
29854 //Strip out comments.
29855 try {
29856 var preamble = '',
29857 commonJsProps = parse.usesCommonJs(fileName, fileContents);
29858
29859 //First see if the module is not already RequireJS-formatted.
29860 if (parse.usesAmdOrRequireJs(fileName, fileContents) || !commonJsProps) {
29861 return fileContents;
29862 }
29863
29864 if (commonJsProps.dirname || commonJsProps.filename) {
29865 preamble = 'var __filename = module.uri || "", ' +
29866 '__dirname = __filename.substring(0, __filename.lastIndexOf("/") + 1); ';
29867 }
29868
29869 //Construct the wrapper boilerplate.
29870 fileContents = 'define(function (require, exports, module) {' +
29871 preamble +
29872 fileContents +
29873 '\n});\n';
29874
29875 } catch (e) {
29876 console.log("commonJs.convert: COULD NOT CONVERT: " + fileName + ", so skipping it. Error was: " + e);
29877 return fileContents;
29878 }
29879
29880 return fileContents;
29881 }
29882 };
29883
29884 return commonJs;
29885});
29886/**
29887 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
29888 * Available via the MIT or new BSD license.
29889 * see: http://github.com/jrburke/requirejs for details
29890 */
29891
29892/*jslint plusplus: true, nomen: true, regexp: true */
29893/*global define, requirejs, java, process, console */
29894
29895
29896define('build', function (require) {
29897 'use strict';
29898
29899 var build,
29900 lang = require('lang'),
29901 prim = require('prim'),
29902 logger = require('logger'),
29903 file = require('env!env/file'),
29904 parse = require('parse'),
29905 optimize = require('optimize'),
29906 pragma = require('pragma'),
29907 transform = require('transform'),
29908 requirePatch = require('requirePatch'),
29909 env = require('env'),
29910 commonJs = require('commonJs'),
29911 SourceMapGenerator = require('source-map').SourceMapGenerator,
29912 hasProp = lang.hasProp,
29913 getOwn = lang.getOwn,
29914 falseProp = lang.falseProp,
29915 endsWithSemiColonRegExp = /;\s*$/,
29916 endsWithSlashRegExp = /[\/\\]$/,
29917 resourceIsModuleIdRegExp = /^[\w\/\\\.]+$/,
29918 deepCopyProps = {
29919 layer: true
29920 };
29921
29922 //Deep copy a config object, but do not copy over the "layer" property,
29923 //as it can be a deeply nested structure with a full requirejs context.
29924 function copyConfig(obj) {
29925 return lang.deeplikeCopy(obj, deepCopyProps);
29926 }
29927
29928 prim.nextTick = function (fn) {
29929 fn();
29930 };
29931
29932 //Now map require to the outermost requirejs, now that we have
29933 //local dependencies for this module. The rest of the require use is
29934 //manipulating the requirejs loader.
29935 require = requirejs;
29936
29937 //Caching function for performance. Attached to
29938 //require so it can be reused in requirePatch.js. _cachedRawText
29939 //set up by requirePatch.js
29940 require._cacheReadAsync = function (path, encoding) {
29941 var d;
29942
29943 if (lang.hasProp(require._cachedRawText, path)) {
29944 d = prim();
29945 d.resolve(require._cachedRawText[path]);
29946 return d.promise;
29947 } else {
29948 return file.readFileAsync(path, encoding).then(function (text) {
29949 require._cachedRawText[path] = text;
29950 return text;
29951 });
29952 }
29953 };
29954
29955 function makeBuildBaseConfig() {
29956 return {
29957 appDir: "",
29958 pragmas: {},
29959 paths: {},
29960 optimize: "uglify",
29961 optimizeCss: "standard.keepLines.keepWhitespace",
29962 inlineText: true,
29963 isBuild: true,
29964 optimizeAllPluginResources: false,
29965 findNestedDependencies: false,
29966 preserveLicenseComments: true,
29967 //By default, all files/directories are copied, unless
29968 //they match this regexp, by default just excludes .folders
29969 dirExclusionRegExp: file.dirExclusionRegExp,
29970 _buildPathToModuleIndex: {}
29971 };
29972 }
29973
29974 /**
29975 * Some JS may not be valid if concatenated with other JS, in particular
29976 * the style of omitting semicolons and rely on ASI. Add a semicolon in
29977 * those cases.
29978 */
29979 function addSemiColon(text, config) {
29980 if (config.skipSemiColonInsertion || endsWithSemiColonRegExp.test(text)) {
29981 return text;
29982 } else {
29983 return text + ";";
29984 }
29985 }
29986
29987 function endsWithSlash(dirName) {
29988 if (dirName.charAt(dirName.length - 1) !== "/") {
29989 dirName += "/";
29990 }
29991 return dirName;
29992 }
29993
29994 //Method used by plugin writeFile calls, defined up here to avoid
29995 //jslint warning about "making a function in a loop".
29996 function makeWriteFile(namespace, layer) {
29997 function writeFile(name, contents) {
29998 logger.trace('Saving plugin-optimized file: ' + name);
29999 file.saveUtf8File(name, contents);
30000 }
30001
30002 writeFile.asModule = function (moduleName, fileName, contents) {
30003 writeFile(fileName,
30004 build.toTransport(namespace, moduleName, fileName, contents, layer));
30005 };
30006
30007 return writeFile;
30008 }
30009
30010 /**
30011 * Main API entry point into the build. The args argument can either be
30012 * an array of arguments (like the onese passed on a command-line),
30013 * or it can be a JavaScript object that has the format of a build profile
30014 * file.
30015 *
30016 * If it is an object, then in addition to the normal properties allowed in
30017 * a build profile file, the object should contain one other property:
30018 *
30019 * The object could also contain a "buildFile" property, which is a string
30020 * that is the file path to a build profile that contains the rest
30021 * of the build profile directives.
30022 *
30023 * This function does not return a status, it should throw an error if
30024 * there is a problem completing the build.
30025 */
30026 build = function (args) {
30027 var buildFile, cmdConfig, errorMsg, errorStack, stackMatch, errorTree,
30028 i, j, errorMod,
30029 stackRegExp = /( {4}at[^\n]+)\n/,
30030 standardIndent = ' ';
30031
30032 return prim().start(function () {
30033 if (!args || lang.isArray(args)) {
30034 if (!args || args.length < 1) {
30035 logger.error("build.js buildProfile.js\n" +
30036 "where buildProfile.js is the name of the build file (see example.build.js for hints on how to make a build file).");
30037 return undefined;
30038 }
30039
30040 //Next args can include a build file path as well as other build args.
30041 //build file path comes first. If it does not contain an = then it is
30042 //a build file path. Otherwise, just all build args.
30043 if (args[0].indexOf("=") === -1) {
30044 buildFile = args[0];
30045 args.splice(0, 1);
30046 }
30047
30048 //Remaining args are options to the build
30049 cmdConfig = build.convertArrayToObject(args);
30050 cmdConfig.buildFile = buildFile;
30051 } else {
30052 cmdConfig = args;
30053 }
30054
30055 return build._run(cmdConfig);
30056 }).then(null, function (e) {
30057 var err;
30058
30059 errorMsg = e.toString();
30060 errorTree = e.moduleTree;
30061 stackMatch = stackRegExp.exec(errorMsg);
30062
30063 if (stackMatch) {
30064 errorMsg += errorMsg.substring(0, stackMatch.index + stackMatch[0].length + 1);
30065 }
30066
30067 //If a module tree that shows what module triggered the error,
30068 //print it out.
30069 if (errorTree && errorTree.length > 0) {
30070 errorMsg += '\nIn module tree:\n';
30071
30072 for (i = errorTree.length - 1; i > -1; i--) {
30073 errorMod = errorTree[i];
30074 if (errorMod) {
30075 for (j = errorTree.length - i; j > -1; j--) {
30076 errorMsg += standardIndent;
30077 }
30078 errorMsg += errorMod + '\n';
30079 }
30080 }
30081
30082 logger.error(errorMsg);
30083 }
30084
30085 errorStack = e.stack;
30086
30087 if (typeof args === 'string' && args.indexOf('stacktrace=true') !== -1) {
30088 errorMsg += '\n' + errorStack;
30089 } else {
30090 if (!stackMatch && errorStack) {
30091 //Just trim out the first "at" in the stack.
30092 stackMatch = stackRegExp.exec(errorStack);
30093 if (stackMatch) {
30094 errorMsg += '\n' + stackMatch[0] || '';
30095 }
30096 }
30097 }
30098
30099 err = new Error(errorMsg);
30100 err.originalError = e;
30101 throw err;
30102 });
30103 };
30104
30105 build._run = function (cmdConfig) {
30106 var buildPaths, fileName, fileNames,
30107 paths, i,
30108 baseConfig, config,
30109 modules, srcPath, buildContext,
30110 destPath, moduleMap, parentModuleMap, context,
30111 resources, resource, plugin, fileContents,
30112 pluginProcessed = {},
30113 buildFileContents = "",
30114 pluginCollector = {};
30115
30116 return prim().start(function () {
30117 var prop;
30118
30119 //Can now run the patches to require.js to allow it to be used for
30120 //build generation. Do it here instead of at the top of the module
30121 //because we want normal require behavior to load the build tool
30122 //then want to switch to build mode.
30123 requirePatch();
30124
30125 config = build.createConfig(cmdConfig);
30126 paths = config.paths;
30127
30128 //Remove the previous build dir, in case it contains source transforms,
30129 //like the ones done with onBuildRead and onBuildWrite.
30130 if (config.dir && !config.keepBuildDir && file.exists(config.dir)) {
30131 file.deleteFile(config.dir);
30132 }
30133
30134 if (!config.out && !config.cssIn) {
30135 //This is not just a one-off file build but a full build profile, with
30136 //lots of files to process.
30137
30138 //First copy all the baseUrl content
30139 file.copyDir((config.appDir || config.baseUrl), config.dir, /\w/, true);
30140
30141 //Adjust baseUrl if config.appDir is in play, and set up build output paths.
30142 buildPaths = {};
30143 if (config.appDir) {
30144 //All the paths should be inside the appDir, so just adjust
30145 //the paths to use the dirBaseUrl
30146 for (prop in paths) {
30147 if (hasProp(paths, prop)) {
30148 buildPaths[prop] = paths[prop].replace(config.appDir, config.dir);
30149 }
30150 }
30151 } else {
30152 //If no appDir, then make sure to copy the other paths to this directory.
30153 for (prop in paths) {
30154 if (hasProp(paths, prop)) {
30155 //Set up build path for each path prefix, but only do so
30156 //if the path falls out of the current baseUrl
30157 if (paths[prop].indexOf(config.baseUrl) === 0) {
30158 buildPaths[prop] = paths[prop].replace(config.baseUrl, config.dirBaseUrl);
30159 } else {
30160 buildPaths[prop] = paths[prop] === 'empty:' ? 'empty:' : prop;
30161
30162 //Make sure source path is fully formed with baseUrl,
30163 //if it is a relative URL.
30164 srcPath = paths[prop];
30165 if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) {
30166 srcPath = config.baseUrl + srcPath;
30167 }
30168
30169 destPath = config.dirBaseUrl + buildPaths[prop];
30170
30171 //Skip empty: paths
30172 if (srcPath !== 'empty:') {
30173 //If the srcPath is a directory, copy the whole directory.
30174 if (file.exists(srcPath) && file.isDirectory(srcPath)) {
30175 //Copy files to build area. Copy all files (the /\w/ regexp)
30176 file.copyDir(srcPath, destPath, /\w/, true);
30177 } else {
30178 //Try a .js extension
30179 srcPath += '.js';
30180 destPath += '.js';
30181 file.copyFile(srcPath, destPath);
30182 }
30183 }
30184 }
30185 }
30186 }
30187 }
30188 }
30189
30190 //Figure out source file location for each module layer. Do this by seeding require
30191 //with source area configuration. This is needed so that later the module layers
30192 //can be manually copied over to the source area, since the build may be
30193 //require multiple times and the above copyDir call only copies newer files.
30194 require({
30195 baseUrl: config.baseUrl,
30196 paths: paths,
30197 packagePaths: config.packagePaths,
30198 packages: config.packages
30199 });
30200 buildContext = require.s.contexts._;
30201 modules = config.modules;
30202
30203 if (modules) {
30204 modules.forEach(function (module) {
30205 if (module.name) {
30206 module._sourcePath = buildContext.nameToUrl(module.name);
30207 //If the module does not exist, and this is not a "new" module layer,
30208 //as indicated by a true "create" property on the module, and
30209 //it is not a plugin-loaded resource, and there is no
30210 //'rawText' containing the module's source then throw an error.
30211 if (!file.exists(module._sourcePath) && !module.create &&
30212 module.name.indexOf('!') === -1 &&
30213 (!config.rawText || !lang.hasProp(config.rawText, module.name))) {
30214 throw new Error("ERROR: module path does not exist: " +
30215 module._sourcePath + " for module named: " + module.name +
30216 ". Path is relative to: " + file.absPath('.'));
30217 }
30218 }
30219 });
30220 }
30221
30222 if (config.out) {
30223 //Just set up the _buildPath for the module layer.
30224 require(config);
30225 if (!config.cssIn) {
30226 config.modules[0]._buildPath = typeof config.out === 'function' ?
30227 'FUNCTION' : config.out;
30228 }
30229 } else if (!config.cssIn) {
30230 //Now set up the config for require to use the build area, and calculate the
30231 //build file locations. Pass along any config info too.
30232 baseConfig = {
30233 baseUrl: config.dirBaseUrl,
30234 paths: buildPaths
30235 };
30236
30237 lang.mixin(baseConfig, config);
30238 require(baseConfig);
30239
30240 if (modules) {
30241 modules.forEach(function (module) {
30242 if (module.name) {
30243 module._buildPath = buildContext.nameToUrl(module.name, null);
30244
30245 //If buildPath and sourcePath are the same, throw since this
30246 //would result in modifying source. This condition can happen
30247 //with some more tricky paths: config and appDir/baseUrl
30248 //setting, which is a sign of incorrect config.
30249 if (module._buildPath === module._sourcePath &&
30250 !config.allowSourceOverwrites) {
30251 throw new Error('Module ID \'' + module.name +
30252 '\' has a source path that is same as output path: ' +
30253 module._sourcePath +
30254 '. Stopping, config is malformed.');
30255 }
30256
30257 if (!module.create) {
30258 file.copyFile(module._sourcePath, module._buildPath);
30259 }
30260 }
30261 });
30262 }
30263 }
30264
30265 //Run CSS optimizations before doing JS module tracing, to allow
30266 //things like text loader plugins loading CSS to get the optimized
30267 //CSS.
30268 if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) {
30269 buildFileContents += optimize.css(config.dir, config);
30270 }
30271 }).then(function() {
30272 baseConfig = copyConfig(require.s.contexts._.config);
30273 }).then(function () {
30274 var actions = [];
30275
30276 if (modules) {
30277 actions = modules.map(function (module, i) {
30278 return function () {
30279 //Save off buildPath to module index in a hash for quicker
30280 //lookup later.
30281 config._buildPathToModuleIndex[file.normalize(module._buildPath)] = i;
30282
30283 //Call require to calculate dependencies.
30284 return build.traceDependencies(module, config, baseConfig)
30285 .then(function (layer) {
30286 module.layer = layer;
30287 });
30288 };
30289 });
30290
30291 return prim.serial(actions);
30292 }
30293 }).then(function () {
30294 var actions;
30295
30296 if (modules) {
30297 //Now build up shadow layers for anything that should be excluded.
30298 //Do this after tracing dependencies for each module, in case one
30299 //of those modules end up being one of the excluded values.
30300 actions = modules.map(function (module) {
30301 return function () {
30302 if (module.exclude) {
30303 module.excludeLayers = [];
30304 return prim.serial(module.exclude.map(function (exclude, i) {
30305 return function () {
30306 //See if it is already in the list of modules.
30307 //If not trace dependencies for it.
30308 var found = build.findBuildModule(exclude, modules);
30309 if (found) {
30310 module.excludeLayers[i] = found;
30311 } else {
30312 return build.traceDependencies({name: exclude}, config, baseConfig)
30313 .then(function (layer) {
30314 module.excludeLayers[i] = { layer: layer };
30315 });
30316 }
30317 };
30318 }));
30319 }
30320 };
30321 });
30322
30323 return prim.serial(actions);
30324 }
30325 }).then(function () {
30326 if (modules) {
30327 return prim.serial(modules.map(function (module) {
30328 return function () {
30329 if (module.exclude) {
30330 //module.exclude is an array of module names. For each one,
30331 //get the nested dependencies for it via a matching entry
30332 //in the module.excludeLayers array.
30333 module.exclude.forEach(function (excludeModule, i) {
30334 var excludeLayer = module.excludeLayers[i].layer,
30335 map = excludeLayer.buildFileToModule;
30336 excludeLayer.buildFilePaths.forEach(function(filePath){
30337 build.removeModulePath(map[filePath], filePath, module.layer);
30338 });
30339 });
30340 }
30341 if (module.excludeShallow) {
30342 //module.excludeShallow is an array of module names.
30343 //shallow exclusions are just that module itself, and not
30344 //its nested dependencies.
30345 module.excludeShallow.forEach(function (excludeShallowModule) {
30346 var path = getOwn(module.layer.buildPathMap, excludeShallowModule);
30347 if (path) {
30348 build.removeModulePath(excludeShallowModule, path, module.layer);
30349 }
30350 });
30351 }
30352
30353 //Flatten them and collect the build output for each module.
30354 return build.flattenModule(module, module.layer, config).then(function (builtModule) {
30355 var finalText, baseName;
30356 //Save it to a temp file for now, in case there are other layers that
30357 //contain optimized content that should not be included in later
30358 //layer optimizations. See issue #56.
30359 if (module._buildPath === 'FUNCTION') {
30360 module._buildText = builtModule.text;
30361 module._buildSourceMap = builtModule.sourceMap;
30362 } else {
30363 finalText = builtModule.text;
30364 if (builtModule.sourceMap) {
30365 baseName = module._buildPath.split('/');
30366 baseName = baseName.pop();
30367 finalText += '\n//# sourceMappingURL=' + baseName + '.map';
30368 file.saveUtf8File(module._buildPath + '.map', builtModule.sourceMap);
30369 }
30370 file.saveUtf8File(module._buildPath + '-temp', finalText);
30371
30372 }
30373 buildFileContents += builtModule.buildText;
30374 });
30375 };
30376 }));
30377 }
30378 }).then(function () {
30379 var moduleName, outOrigSourceMap;
30380 if (modules) {
30381 //Now move the build layers to their final position.
30382 modules.forEach(function (module) {
30383 var finalPath = module._buildPath;
30384 if (finalPath !== 'FUNCTION') {
30385 if (file.exists(finalPath)) {
30386 file.deleteFile(finalPath);
30387 }
30388 file.renameFile(finalPath + '-temp', finalPath);
30389
30390 //And finally, if removeCombined is specified, remove
30391 //any of the files that were used in this layer.
30392 //Be sure not to remove other build layers.
30393 if (config.removeCombined && !config.out) {
30394 module.layer.buildFilePaths.forEach(function (path) {
30395 var isLayer = modules.some(function (mod) {
30396 return mod._buildPath === path;
30397 }),
30398 relPath = build.makeRelativeFilePath(config.dir, path);
30399
30400 if (file.exists(path) &&
30401 // not a build layer target
30402 !isLayer &&
30403 // not outside the build directory
30404 relPath.indexOf('..') !== 0) {
30405 file.deleteFile(path);
30406 }
30407 });
30408 }
30409 }
30410
30411 //Signal layer is done
30412 if (config.onModuleBundleComplete) {
30413 config.onModuleBundleComplete(module.onCompleteData);
30414 }
30415 });
30416 }
30417
30418 //If removeCombined in play, remove any empty directories that
30419 //may now exist because of its use
30420 if (config.removeCombined && !config.out && config.dir) {
30421 file.deleteEmptyDirs(config.dir);
30422 }
30423
30424 //Do other optimizations.
30425 if (config.out && !config.cssIn) {
30426 //Just need to worry about one JS file.
30427 fileName = config.modules[0]._buildPath;
30428 if (fileName === 'FUNCTION') {
30429 outOrigSourceMap = config.modules[0]._buildSourceMap;
30430 config._buildSourceMap = outOrigSourceMap;
30431 config.modules[0]._buildText = optimize.js((config.modules[0].name ||
30432 config.modules[0].include[0] ||
30433 fileName) + '.build.js',
30434 config.modules[0]._buildText,
30435 null,
30436 config);
30437 if (config._buildSourceMap && config._buildSourceMap !== outOrigSourceMap) {
30438 config.modules[0]._buildSourceMap = config._buildSourceMap;
30439 config._buildSourceMap = null;
30440 }
30441 } else {
30442 optimize.jsFile(fileName, null, fileName, config);
30443 }
30444 } else if (!config.cssIn) {
30445 //Normal optimizations across modules.
30446
30447 //JS optimizations.
30448 fileNames = file.getFilteredFileList(config.dir, /\.js$/, true);
30449 fileNames.forEach(function (fileName) {
30450 var cfg, override, moduleIndex;
30451
30452 //Generate the module name from the config.dir root.
30453 moduleName = fileName.replace(config.dir, '');
30454 //Get rid of the extension
30455 moduleName = moduleName.substring(0, moduleName.length - 3);
30456
30457 //If there is an override for a specific layer build module,
30458 //and this file is that module, mix in the override for use
30459 //by optimize.jsFile.
30460 moduleIndex = getOwn(config._buildPathToModuleIndex, fileName);
30461 //Normalize, since getOwn could have returned undefined
30462 moduleIndex = moduleIndex === 0 || moduleIndex > 0 ? moduleIndex : -1;
30463
30464 //Try to avoid extra work if the other files do not need to
30465 //be read. Build layers should be processed at the very
30466 //least for optimization.
30467 if (moduleIndex > -1 || !config.skipDirOptimize ||
30468 config.normalizeDirDefines === "all" ||
30469 config.cjsTranslate) {
30470 //Convert the file to transport format, but without a name
30471 //inserted (by passing null for moduleName) since the files are
30472 //standalone, one module per file.
30473 fileContents = file.readFile(fileName);
30474
30475
30476 //For builds, if wanting cjs translation, do it now, so that
30477 //the individual modules can be loaded cross domain via
30478 //plain script tags.
30479 if (config.cjsTranslate &&
30480 (!config.shim || !lang.hasProp(config.shim, moduleName))) {
30481 fileContents = commonJs.convert(fileName, fileContents);
30482 }
30483
30484 if (moduleIndex === -1) {
30485 if (config.onBuildRead) {
30486 fileContents = config.onBuildRead(moduleName,
30487 fileName,
30488 fileContents);
30489 }
30490
30491 //Only do transport normalization if this is not a build
30492 //layer (since it was already normalized) and if
30493 //normalizeDirDefines indicated all should be done.
30494 if (config.normalizeDirDefines === "all") {
30495 fileContents = build.toTransport(config.namespace,
30496 null,
30497 fileName,
30498 fileContents);
30499 }
30500
30501 if (config.onBuildWrite) {
30502 fileContents = config.onBuildWrite(moduleName,
30503 fileName,
30504 fileContents);
30505 }
30506 }
30507
30508 override = moduleIndex > -1 ?
30509 config.modules[moduleIndex].override : null;
30510 if (override) {
30511 cfg = build.createOverrideConfig(config, override);
30512 } else {
30513 cfg = config;
30514 }
30515
30516 if (moduleIndex > -1 || !config.skipDirOptimize) {
30517 optimize.jsFile(fileName, fileContents, fileName, cfg, pluginCollector);
30518 }
30519 }
30520 });
30521
30522 //Normalize all the plugin resources.
30523 context = require.s.contexts._;
30524
30525 for (moduleName in pluginCollector) {
30526 if (hasProp(pluginCollector, moduleName)) {
30527 parentModuleMap = context.makeModuleMap(moduleName);
30528 resources = pluginCollector[moduleName];
30529 for (i = 0; i < resources.length; i++) {
30530 resource = resources[i];
30531 moduleMap = context.makeModuleMap(resource, parentModuleMap);
30532 if (falseProp(context.plugins, moduleMap.prefix)) {
30533 //Set the value in context.plugins so it
30534 //will be evaluated as a full plugin.
30535 context.plugins[moduleMap.prefix] = true;
30536
30537 //Do not bother if the plugin is not available.
30538 if (!file.exists(require.toUrl(moduleMap.prefix + '.js'))) {
30539 continue;
30540 }
30541
30542 //Rely on the require in the build environment
30543 //to be synchronous
30544 context.require([moduleMap.prefix]);
30545
30546 //Now that the plugin is loaded, redo the moduleMap
30547 //since the plugin will need to normalize part of the path.
30548 moduleMap = context.makeModuleMap(resource, parentModuleMap);
30549 }
30550
30551 //Only bother with plugin resources that can be handled
30552 //processed by the plugin, via support of the writeFile
30553 //method.
30554 if (falseProp(pluginProcessed, moduleMap.id)) {
30555 //Only do the work if the plugin was really loaded.
30556 //Using an internal access because the file may
30557 //not really be loaded.
30558 plugin = getOwn(context.defined, moduleMap.prefix);
30559 if (plugin && plugin.writeFile) {
30560 plugin.writeFile(
30561 moduleMap.prefix,
30562 moduleMap.name,
30563 require,
30564 makeWriteFile(
30565 config.namespace
30566 ),
30567 context.config
30568 );
30569 }
30570
30571 pluginProcessed[moduleMap.id] = true;
30572 }
30573 }
30574
30575 }
30576 }
30577
30578 //console.log('PLUGIN COLLECTOR: ' + JSON.stringify(pluginCollector, null, " "));
30579
30580
30581 //All module layers are done, write out the build.txt file.
30582 file.saveUtf8File(config.dir + "build.txt", buildFileContents);
30583 }
30584
30585 //If just have one CSS file to optimize, do that here.
30586 if (config.cssIn) {
30587 buildFileContents += optimize.cssFile(config.cssIn, config.out, config).buildText;
30588 }
30589
30590 if (typeof config.out === 'function') {
30591 config.out(config.modules[0]._buildText, config.modules[0]._buildSourceMap);
30592 }
30593
30594 //Print out what was built into which layers.
30595 if (buildFileContents) {
30596 logger.info(buildFileContents);
30597 return buildFileContents;
30598 }
30599
30600 return '';
30601 });
30602 };
30603
30604 /**
30605 * Converts command line args like "paths.foo=../some/path"
30606 * result.paths = { foo: '../some/path' } where prop = paths,
30607 * name = paths.foo and value = ../some/path, so it assumes the
30608 * name=value splitting has already happened.
30609 */
30610 function stringDotToObj(result, name, value) {
30611 var parts = name.split('.');
30612
30613 parts.forEach(function (prop, i) {
30614 if (i === parts.length - 1) {
30615 result[prop] = value;
30616 } else {
30617 if (falseProp(result, prop)) {
30618 result[prop] = {};
30619 }
30620 result = result[prop];
30621 }
30622
30623 });
30624 }
30625
30626 build.objProps = {
30627 paths: true,
30628 wrap: true,
30629 pragmas: true,
30630 pragmasOnSave: true,
30631 has: true,
30632 hasOnSave: true,
30633 uglify: true,
30634 uglify2: true,
30635 closure: true,
30636 map: true,
30637 throwWhen: true
30638 };
30639
30640 build.hasDotPropMatch = function (prop) {
30641 var dotProp,
30642 index = prop.indexOf('.');
30643
30644 if (index !== -1) {
30645 dotProp = prop.substring(0, index);
30646 return hasProp(build.objProps, dotProp);
30647 }
30648 return false;
30649 };
30650
30651 /**
30652 * Converts an array that has String members of "name=value"
30653 * into an object, where the properties on the object are the names in the array.
30654 * Also converts the strings "true" and "false" to booleans for the values.
30655 * member name/value pairs, and converts some comma-separated lists into
30656 * arrays.
30657 * @param {Array} ary
30658 */
30659 build.convertArrayToObject = function (ary) {
30660 var result = {}, i, separatorIndex, prop, value,
30661 needArray = {
30662 "include": true,
30663 "exclude": true,
30664 "excludeShallow": true,
30665 "insertRequire": true,
30666 "stubModules": true,
30667 "deps": true,
30668 "mainConfigFile": true
30669 };
30670
30671 for (i = 0; i < ary.length; i++) {
30672 separatorIndex = ary[i].indexOf("=");
30673 if (separatorIndex === -1) {
30674 throw "Malformed name/value pair: [" + ary[i] + "]. Format should be name=value";
30675 }
30676
30677 value = ary[i].substring(separatorIndex + 1, ary[i].length);
30678 if (value === "true") {
30679 value = true;
30680 } else if (value === "false") {
30681 value = false;
30682 }
30683
30684 prop = ary[i].substring(0, separatorIndex);
30685
30686 //Convert to array if necessary
30687 if (getOwn(needArray, prop)) {
30688 value = value.split(",");
30689 }
30690
30691 if (build.hasDotPropMatch(prop)) {
30692 stringDotToObj(result, prop, value);
30693 } else {
30694 result[prop] = value;
30695 }
30696 }
30697 return result; //Object
30698 };
30699
30700 build.makeAbsPath = function (path, absFilePath) {
30701 if (!absFilePath) {
30702 return path;
30703 }
30704
30705 //Add abspath if necessary. If path starts with a slash or has a colon,
30706 //then already is an abolute path.
30707 if (path.indexOf('/') !== 0 && path.indexOf(':') === -1) {
30708 path = absFilePath +
30709 (absFilePath.charAt(absFilePath.length - 1) === '/' ? '' : '/') +
30710 path;
30711 path = file.normalize(path);
30712 }
30713 return path.replace(lang.backSlashRegExp, '/');
30714 };
30715
30716 build.makeAbsObject = function (props, obj, absFilePath) {
30717 var i, prop;
30718 if (obj) {
30719 for (i = 0; i < props.length; i++) {
30720 prop = props[i];
30721 if (hasProp(obj, prop) && typeof obj[prop] === 'string') {
30722 obj[prop] = build.makeAbsPath(obj[prop], absFilePath);
30723 }
30724 }
30725 }
30726 };
30727
30728 /**
30729 * For any path in a possible config, make it absolute relative
30730 * to the absFilePath passed in.
30731 */
30732 build.makeAbsConfig = function (config, absFilePath) {
30733 var props, prop, i;
30734
30735 props = ["appDir", "dir", "baseUrl"];
30736 for (i = 0; i < props.length; i++) {
30737 prop = props[i];
30738
30739 if (getOwn(config, prop)) {
30740 //Add abspath if necessary, make sure these paths end in
30741 //slashes
30742 if (prop === "baseUrl") {
30743 config.originalBaseUrl = config.baseUrl;
30744 if (config.appDir) {
30745 //If baseUrl with an appDir, the baseUrl is relative to
30746 //the appDir, *not* the absFilePath. appDir and dir are
30747 //made absolute before baseUrl, so this will work.
30748 config.baseUrl = build.makeAbsPath(config.originalBaseUrl, config.appDir);
30749 } else {
30750 //The dir output baseUrl is same as regular baseUrl, both
30751 //relative to the absFilePath.
30752 config.baseUrl = build.makeAbsPath(config[prop], absFilePath);
30753 }
30754 } else {
30755 config[prop] = build.makeAbsPath(config[prop], absFilePath);
30756 }
30757
30758 config[prop] = endsWithSlash(config[prop]);
30759 }
30760 }
30761
30762 build.makeAbsObject((config.out === "stdout" ? ["cssIn"] : ["out", "cssIn"]),
30763 config, absFilePath);
30764 build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath);
30765 build.makeAbsObject(["externExportsPath"], config.closure, absFilePath);
30766 };
30767
30768 /**
30769 * Creates a relative path to targetPath from refPath.
30770 * Only deals with file paths, not folders. If folders,
30771 * make sure paths end in a trailing '/'.
30772 */
30773 build.makeRelativeFilePath = function (refPath, targetPath) {
30774 var i, dotLength, finalParts, length, targetParts, targetName,
30775 refParts = refPath.split('/'),
30776 hasEndSlash = endsWithSlashRegExp.test(targetPath),
30777 dotParts = [];
30778
30779 targetPath = file.normalize(targetPath);
30780 if (hasEndSlash && !endsWithSlashRegExp.test(targetPath)) {
30781 targetPath += '/';
30782 }
30783 targetParts = targetPath.split('/');
30784 //Pull off file name
30785 targetName = targetParts.pop();
30786
30787 //Also pop off the ref file name to make the matches against
30788 //targetParts equivalent.
30789 refParts.pop();
30790
30791 length = refParts.length;
30792
30793 for (i = 0; i < length; i += 1) {
30794 if (refParts[i] !== targetParts[i]) {
30795 break;
30796 }
30797 }
30798
30799 //Now i is the index in which they diverge.
30800 finalParts = targetParts.slice(i);
30801
30802 dotLength = length - i;
30803 for (i = 0; i > -1 && i < dotLength; i += 1) {
30804 dotParts.push('..');
30805 }
30806
30807 return dotParts.join('/') + (dotParts.length ? '/' : '') +
30808 finalParts.join('/') + (finalParts.length ? '/' : '') +
30809 targetName;
30810 };
30811
30812 build.nestedMix = {
30813 paths: true,
30814 has: true,
30815 hasOnSave: true,
30816 pragmas: true,
30817 pragmasOnSave: true
30818 };
30819
30820 /**
30821 * Mixes additional source config into target config, and merges some
30822 * nested config, like paths, correctly.
30823 */
30824 function mixConfig(target, source, skipArrays) {
30825 var prop, value, isArray, targetValue;
30826
30827 for (prop in source) {
30828 if (hasProp(source, prop)) {
30829 //If the value of the property is a plain object, then
30830 //allow a one-level-deep mixing of it.
30831 value = source[prop];
30832 isArray = lang.isArray(value);
30833 if (typeof value === 'object' && value &&
30834 !isArray && !lang.isFunction(value) &&
30835 !lang.isRegExp(value)) {
30836
30837 // TODO: need to generalize this work, maybe also reuse
30838 // the work done in requirejs configure, perhaps move to
30839 // just a deep copy/merge overall. However, given the
30840 // amount of observable change, wait for a dot release.
30841 // This change is in relation to #645
30842 if (prop === 'map') {
30843 if (!target.map) {
30844 target.map = {};
30845 }
30846 lang.deepMix(target.map, source.map);
30847 } else {
30848 target[prop] = lang.mixin({}, target[prop], value, true);
30849 }
30850 } else if (isArray) {
30851 if (!skipArrays) {
30852 // Some config, like packages, are arrays. For those,
30853 // just merge the results.
30854 targetValue = target[prop];
30855 if (lang.isArray(targetValue)) {
30856 target[prop] = targetValue.concat(value);
30857 } else {
30858 target[prop] = value;
30859 }
30860 }
30861 } else {
30862 target[prop] = value;
30863 }
30864 }
30865 }
30866
30867 //Set up log level since it can affect if errors are thrown
30868 //or caught and passed to errbacks while doing config setup.
30869 if (lang.hasProp(target, 'logLevel')) {
30870 logger.logLevel(target.logLevel);
30871 }
30872 }
30873
30874 /**
30875 * Converts a wrap.startFile or endFile to be start/end as a string.
30876 * the startFile/endFile values can be arrays.
30877 */
30878 function flattenWrapFile(wrap, keyName, absFilePath) {
30879 var keyFileName = keyName + 'File';
30880
30881 if (typeof wrap[keyName] !== 'string' && wrap[keyFileName]) {
30882 wrap[keyName] = '';
30883 if (typeof wrap[keyFileName] === 'string') {
30884 wrap[keyFileName] = [wrap[keyFileName]];
30885 }
30886 wrap[keyFileName].forEach(function (fileName) {
30887 wrap[keyName] += (wrap[keyName] ? '\n' : '') +
30888 file.readFile(build.makeAbsPath(fileName, absFilePath));
30889 });
30890 } else if (wrap[keyName] === null || wrap[keyName] === undefined) {
30891 //Allow missing one, just set to empty string.
30892 wrap[keyName] = '';
30893 } else if (typeof wrap[keyName] !== 'string') {
30894 throw new Error('wrap.' + keyName + ' or wrap.' + keyFileName + ' malformed');
30895 }
30896 }
30897
30898 function normalizeWrapConfig(config, absFilePath) {
30899 //Get any wrap text.
30900 try {
30901 if (config.wrap) {
30902 if (config.wrap === true) {
30903 //Use default values.
30904 config.wrap = {
30905 start: '(function () {',
30906 end: '}());'
30907 };
30908 } else {
30909 flattenWrapFile(config.wrap, 'start', absFilePath);
30910 flattenWrapFile(config.wrap, 'end', absFilePath);
30911 }
30912 }
30913 } catch (wrapError) {
30914 throw new Error('Malformed wrap config: ' + wrapError.toString());
30915 }
30916 }
30917
30918 /**
30919 * Creates a config object for an optimization build.
30920 * It will also read the build profile if it is available, to create
30921 * the configuration.
30922 *
30923 * @param {Object} cfg config options that take priority
30924 * over defaults and ones in the build file. These options could
30925 * be from a command line, for instance.
30926 *
30927 * @param {Object} the created config object.
30928 */
30929 build.createConfig = function (cfg) {
30930 /*jslint evil: true */
30931 var buildFileContents, buildFileConfig, mainConfig,
30932 mainConfigFile, mainConfigPath, buildFile, absFilePath,
30933 config = {},
30934 buildBaseConfig = makeBuildBaseConfig();
30935
30936 //Make sure all paths are relative to current directory.
30937 absFilePath = file.absPath('.');
30938 build.makeAbsConfig(cfg, absFilePath);
30939 build.makeAbsConfig(buildBaseConfig, absFilePath);
30940
30941 lang.mixin(config, buildBaseConfig);
30942 lang.mixin(config, cfg, true);
30943
30944 //Set up log level early since it can affect if errors are thrown
30945 //or caught and passed to errbacks, even while constructing config.
30946 if (lang.hasProp(config, 'logLevel')) {
30947 logger.logLevel(config.logLevel);
30948 }
30949
30950 if (config.buildFile) {
30951 //A build file exists, load it to get more config.
30952 buildFile = file.absPath(config.buildFile);
30953
30954 //Find the build file, and make sure it exists, if this is a build
30955 //that has a build profile, and not just command line args with an in=path
30956 if (!file.exists(buildFile)) {
30957 throw new Error("ERROR: build file does not exist: " + buildFile);
30958 }
30959
30960 absFilePath = config.baseUrl = file.absPath(file.parent(buildFile));
30961
30962 //Load build file options.
30963 buildFileContents = file.readFile(buildFile);
30964 try {
30965 //Be a bit lenient in the file ending in a ; or ending with
30966 //a //# sourceMappingUrl comment, mostly for compiled languages
30967 //that create a config, like typescript.
30968 buildFileContents = buildFileContents
30969 .replace(/\/\/\#[^\n\r]+[\n\r]*$/, '')
30970 .trim()
30971 .replace(/;$/, '');
30972
30973 buildFileConfig = eval("(" + buildFileContents + ")");
30974 build.makeAbsConfig(buildFileConfig, absFilePath);
30975
30976 //Mix in the config now so that items in mainConfigFile can
30977 //be resolved relative to them if necessary, like if appDir
30978 //is set here, but the baseUrl is in mainConfigFile. Will
30979 //re-mix in the same build config later after mainConfigFile
30980 //is processed, since build config should take priority.
30981 mixConfig(config, buildFileConfig);
30982 } catch (e) {
30983 throw new Error("Build file " + buildFile + " is malformed: " + e);
30984 }
30985 }
30986
30987 mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile);
30988 if (mainConfigFile) {
30989 if (typeof mainConfigFile === 'string') {
30990 mainConfigFile = [mainConfigFile];
30991 }
30992
30993 mainConfigFile.forEach(function (configFile) {
30994 configFile = build.makeAbsPath(configFile, absFilePath);
30995 if (!file.exists(configFile)) {
30996 throw new Error(configFile + ' does not exist.');
30997 }
30998 try {
30999 mainConfig = parse.findConfig(file.readFile(configFile)).config;
31000 } catch (configError) {
31001 throw new Error('The config in mainConfigFile ' +
31002 configFile +
31003 ' cannot be used because it cannot be evaluated' +
31004 ' correctly while running in the optimizer. Try only' +
31005 ' using a config that is also valid JSON, or do not use' +
31006 ' mainConfigFile and instead copy the config values needed' +
31007 ' into a build file or command line arguments given to the optimizer.\n' +
31008 'Source error from parsing: ' + configFile + ': ' + configError);
31009 }
31010 if (mainConfig) {
31011 mainConfigPath = configFile.substring(0, configFile.lastIndexOf('/'));
31012
31013 //Add in some existing config, like appDir, since they can be
31014 //used inside the configFile -- paths and baseUrl are
31015 //relative to them.
31016 if (config.appDir && !mainConfig.appDir) {
31017 mainConfig.appDir = config.appDir;
31018 }
31019
31020 //If no baseUrl, then use the directory holding the main config.
31021 if (!mainConfig.baseUrl) {
31022 mainConfig.baseUrl = mainConfigPath;
31023 }
31024
31025 build.makeAbsConfig(mainConfig, mainConfigPath);
31026 mixConfig(config, mainConfig);
31027 }
31028 });
31029 }
31030
31031 //Mix in build file config, but only after mainConfig has been mixed in.
31032 //Since this is a re-application, skip array merging.
31033 if (buildFileConfig) {
31034 mixConfig(config, buildFileConfig, true);
31035 }
31036
31037 //Re-apply the override config values. Command line
31038 //args should take precedence over build file values.
31039 //Since this is a re-application, skip array merging.
31040 mixConfig(config, cfg, true);
31041
31042 //Fix paths to full paths so that they can be adjusted consistently
31043 //lately to be in the output area.
31044 lang.eachProp(config.paths, function (value, prop) {
31045 if (lang.isArray(value)) {
31046 throw new Error('paths fallback not supported in optimizer. ' +
31047 'Please provide a build config path override ' +
31048 'for ' + prop);
31049 }
31050 config.paths[prop] = build.makeAbsPath(value, config.baseUrl);
31051 });
31052
31053 //Set final output dir
31054 if (hasProp(config, "baseUrl")) {
31055 if (config.appDir) {
31056 if (!config.originalBaseUrl) {
31057 throw new Error('Please set a baseUrl in the build config');
31058 }
31059 config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir);
31060 } else {
31061 config.dirBaseUrl = config.dir || config.baseUrl;
31062 }
31063 //Make sure dirBaseUrl ends in a slash, since it is
31064 //concatenated with other strings.
31065 config.dirBaseUrl = endsWithSlash(config.dirBaseUrl);
31066 }
31067
31068
31069 //If out=stdout, write output to STDOUT instead of a file.
31070 if (config.out && config.out === 'stdout') {
31071 config.out = function (content) {
31072 var e = env.get();
31073 if (e === 'rhino') {
31074 var out = new java.io.PrintStream(java.lang.System.out, true, 'UTF-8');
31075 out.println(content);
31076 } else if (e === 'node') {
31077 process.stdout.setEncoding('utf8');
31078 process.stdout.write(content);
31079 } else {
31080 console.log(content);
31081 }
31082 };
31083 }
31084
31085 //Check for errors in config
31086 if (config.main) {
31087 throw new Error('"main" passed as an option, but the ' +
31088 'supported option is called "name".');
31089 }
31090 if (config.out && !config.name && !config.modules && !config.include &&
31091 !config.cssIn) {
31092 throw new Error('Missing either a "name", "include" or "modules" ' +
31093 'option');
31094 }
31095 if (config.cssIn) {
31096 if (config.dir || config.appDir) {
31097 throw new Error('cssIn is only for the output of single file ' +
31098 'CSS optimizations and is not compatible with "dir" or "appDir" configuration.');
31099 }
31100 if (!config.out) {
31101 throw new Error('"out" option missing.');
31102 }
31103 }
31104 if (!config.cssIn && !config.baseUrl) {
31105 //Just use the current directory as the baseUrl
31106 config.baseUrl = './';
31107 }
31108 if (!config.out && !config.dir) {
31109 throw new Error('Missing either an "out" or "dir" config value. ' +
31110 'If using "appDir" for a full project optimization, ' +
31111 'use "dir". If you want to optimize to one file, ' +
31112 'use "out".');
31113 }
31114 if (config.appDir && config.out) {
31115 throw new Error('"appDir" is not compatible with "out". Use "dir" ' +
31116 'instead. appDir is used to copy whole projects, ' +
31117 'where "out" with "baseUrl" is used to just ' +
31118 'optimize to one file.');
31119 }
31120 if (config.out && config.dir) {
31121 throw new Error('The "out" and "dir" options are incompatible.' +
31122 ' Use "out" if you are targeting a single file' +
31123 ' for optimization, and "dir" if you want the appDir' +
31124 ' or baseUrl directories optimized.');
31125 }
31126
31127
31128 if (config.dir) {
31129 // Make sure the output dir is not set to a parent of the
31130 // source dir or the same dir, as it will result in source
31131 // code deletion.
31132 if (!config.allowSourceOverwrites && (config.dir === config.baseUrl ||
31133 config.dir === config.appDir ||
31134 (config.baseUrl && build.makeRelativeFilePath(config.dir,
31135 config.baseUrl).indexOf('..') !== 0) ||
31136 (config.appDir &&
31137 build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0))) {
31138 throw new Error('"dir" is set to a parent or same directory as' +
31139 ' "appDir" or "baseUrl". This can result in' +
31140 ' the deletion of source code. Stopping. If' +
31141 ' you want to allow possible overwriting of' +
31142 ' source code, set "allowSourceOverwrites"' +
31143 ' to true in the build config, but do so at' +
31144 ' your own risk. In that case, you may want' +
31145 ' to also set "keepBuildDir" to true.');
31146 }
31147 }
31148
31149 if (config.insertRequire && !lang.isArray(config.insertRequire)) {
31150 throw new Error('insertRequire should be a list of module IDs' +
31151 ' to insert in to a require([]) call.');
31152 }
31153
31154 if (config.generateSourceMaps) {
31155 if (config.preserveLicenseComments && config.optimize !== 'none') {
31156 throw new Error('Cannot use preserveLicenseComments and ' +
31157 'generateSourceMaps together. Either explcitly set ' +
31158 'preserveLicenseComments to false (default is true) or ' +
31159 'turn off generateSourceMaps. If you want source maps with ' +
31160 'license comments, see: ' +
31161 'http://requirejs.org/docs/errors.html#sourcemapcomments');
31162 } else if (config.optimize !== 'none' &&
31163 config.optimize !== 'closure' &&
31164 config.optimize !== 'uglify2') {
31165 //Allow optimize: none to pass, since it is useful when toggling
31166 //minification on and off to debug something, and it implicitly
31167 //works, since it does not need a source map.
31168 throw new Error('optimize: "' + config.optimize +
31169 '" does not support generateSourceMaps.');
31170 }
31171 }
31172
31173 if ((config.name || config.include) && !config.modules) {
31174 //Just need to build one file, but may be part of a whole appDir/
31175 //baseUrl copy, but specified on the command line, so cannot do
31176 //the modules array setup. So create a modules section in that
31177 //case.
31178 config.modules = [
31179 {
31180 name: config.name,
31181 out: config.out,
31182 create: config.create,
31183 include: config.include,
31184 exclude: config.exclude,
31185 excludeShallow: config.excludeShallow,
31186 insertRequire: config.insertRequire,
31187 stubModules: config.stubModules
31188 }
31189 ];
31190 delete config.stubModules;
31191 } else if (config.modules && config.out) {
31192 throw new Error('If the "modules" option is used, then there ' +
31193 'should be a "dir" option set and "out" should ' +
31194 'not be used since "out" is only for single file ' +
31195 'optimization output.');
31196 } else if (config.modules && config.name) {
31197 throw new Error('"name" and "modules" options are incompatible. ' +
31198 'Either use "name" if doing a single file ' +
31199 'optimization, or "modules" if you want to target ' +
31200 'more than one file for optimization.');
31201 }
31202
31203 if (config.out && !config.cssIn) {
31204 //Just one file to optimize.
31205
31206 //Does not have a build file, so set up some defaults.
31207 //Optimizing CSS should not be allowed, unless explicitly
31208 //asked for on command line. In that case the only task is
31209 //to optimize a CSS file.
31210 if (!cfg.optimizeCss) {
31211 config.optimizeCss = "none";
31212 }
31213 }
31214
31215 //Normalize cssPrefix
31216 if (config.cssPrefix) {
31217 //Make sure cssPrefix ends in a slash
31218 config.cssPrefix = endsWithSlash(config.cssPrefix);
31219 } else {
31220 config.cssPrefix = '';
31221 }
31222
31223 //Cycle through modules and normalize
31224 if (config.modules && config.modules.length) {
31225 config.modules.forEach(function (mod) {
31226 if (lang.isArray(mod) || typeof mod === 'string' || !mod) {
31227 throw new Error('modules config item is malformed: it should' +
31228 ' be an object with a \'name\' property.');
31229 }
31230
31231 //Combine any local stubModules with global values.
31232 if (config.stubModules) {
31233 mod.stubModules = config.stubModules.concat(mod.stubModules || []);
31234 }
31235
31236 //Create a hash lookup for the stubModules config to make lookup
31237 //cheaper later.
31238 if (mod.stubModules) {
31239 mod.stubModules._byName = {};
31240 mod.stubModules.forEach(function (id) {
31241 mod.stubModules._byName[id] = true;
31242 });
31243 }
31244
31245 // Legacy command support, which allowed a single string ID
31246 // for include.
31247 if (typeof mod.include === 'string') {
31248 mod.include = [mod.include];
31249 }
31250
31251 //Allow wrap config in overrides, but normalize it.
31252 if (mod.override) {
31253 normalizeWrapConfig(mod.override, absFilePath);
31254 }
31255 });
31256 }
31257
31258 normalizeWrapConfig(config, absFilePath);
31259
31260 //Do final input verification
31261 if (config.context) {
31262 throw new Error('The build argument "context" is not supported' +
31263 ' in a build. It should only be used in web' +
31264 ' pages.');
31265 }
31266
31267 //Set up normalizeDirDefines. If not explicitly set, if optimize "none",
31268 //set to "skip" otherwise set to "all".
31269 if (!hasProp(config, 'normalizeDirDefines')) {
31270 if (config.optimize === 'none' || config.skipDirOptimize) {
31271 config.normalizeDirDefines = 'skip';
31272 } else {
31273 config.normalizeDirDefines = 'all';
31274 }
31275 }
31276
31277 //Set file.fileExclusionRegExp if desired
31278 if (hasProp(config, 'fileExclusionRegExp')) {
31279 if (typeof config.fileExclusionRegExp === "string") {
31280 file.exclusionRegExp = new RegExp(config.fileExclusionRegExp);
31281 } else {
31282 file.exclusionRegExp = config.fileExclusionRegExp;
31283 }
31284 } else if (hasProp(config, 'dirExclusionRegExp')) {
31285 //Set file.dirExclusionRegExp if desired, this is the old
31286 //name for fileExclusionRegExp before 1.0.2. Support for backwards
31287 //compatibility
31288 file.exclusionRegExp = config.dirExclusionRegExp;
31289 }
31290
31291 //Track the deps, but in a different key, so that they are not loaded
31292 //as part of config seeding before all config is in play (#648). Was
31293 //going to merge this in with "include", but include is added after
31294 //the "name" target. To preserve what r.js has done previously, make
31295 //sure "deps" comes before the "name".
31296 if (config.deps) {
31297 config._depsInclude = config.deps;
31298 }
31299
31300
31301 //Remove things that may cause problems in the build.
31302 //deps already merged above
31303 delete config.deps;
31304 delete config.jQuery;
31305 delete config.enforceDefine;
31306 delete config.urlArgs;
31307
31308 return config;
31309 };
31310
31311 /**
31312 * finds the module being built/optimized with the given moduleName,
31313 * or returns null.
31314 * @param {String} moduleName
31315 * @param {Array} modules
31316 * @returns {Object} the module object from the build profile, or null.
31317 */
31318 build.findBuildModule = function (moduleName, modules) {
31319 var i, module;
31320 for (i = 0; i < modules.length; i++) {
31321 module = modules[i];
31322 if (module.name === moduleName) {
31323 return module;
31324 }
31325 }
31326 return null;
31327 };
31328
31329 /**
31330 * Removes a module name and path from a layer, if it is supposed to be
31331 * excluded from the layer.
31332 * @param {String} moduleName the name of the module
31333 * @param {String} path the file path for the module
31334 * @param {Object} layer the layer to remove the module/path from
31335 */
31336 build.removeModulePath = function (module, path, layer) {
31337 var index = layer.buildFilePaths.indexOf(path);
31338 if (index !== -1) {
31339 layer.buildFilePaths.splice(index, 1);
31340 }
31341 };
31342
31343 /**
31344 * Uses the module build config object to trace the dependencies for the
31345 * given module.
31346 *
31347 * @param {Object} module the module object from the build config info.
31348 * @param {Object} config the build config object.
31349 * @param {Object} [baseLoaderConfig] the base loader config to use for env resets.
31350 *
31351 * @returns {Object} layer information about what paths and modules should
31352 * be in the flattened module.
31353 */
31354 build.traceDependencies = function (module, config, baseLoaderConfig) {
31355 var include, override, layer, context, oldContext,
31356 rawTextByIds,
31357 syncChecks = {
31358 rhino: true,
31359 node: true,
31360 xpconnect: true
31361 },
31362 deferred = prim();
31363
31364 //Reset some state set up in requirePatch.js, and clean up require's
31365 //current context.
31366 oldContext = require._buildReset();
31367
31368 //Grab the reset layer and context after the reset, but keep the
31369 //old config to reuse in the new context.
31370 layer = require._layer;
31371 context = layer.context;
31372
31373 //Put back basic config, use a fresh object for it.
31374 if (baseLoaderConfig) {
31375 require(copyConfig(baseLoaderConfig));
31376 }
31377
31378 logger.trace("\nTracing dependencies for: " + (module.name ||
31379 (typeof module.out === 'function' ? 'FUNCTION' : module.out)));
31380 include = config._depsInclude || [];
31381 include = include.concat(module.name && !module.create ? [module.name] : []);
31382 if (module.include) {
31383 include = include.concat(module.include);
31384 }
31385
31386 //If there are overrides to basic config, set that up now.;
31387 if (module.override) {
31388 if (baseLoaderConfig) {
31389 override = build.createOverrideConfig(baseLoaderConfig, module.override);
31390 } else {
31391 override = copyConfig(module.override);
31392 }
31393 require(override);
31394 }
31395
31396 //Now, populate the rawText cache with any values explicitly passed in
31397 //via config.
31398 rawTextByIds = require.s.contexts._.config.rawText;
31399 if (rawTextByIds) {
31400 lang.eachProp(rawTextByIds, function (contents, id) {
31401 var url = require.toUrl(id) + '.js';
31402 require._cachedRawText[url] = contents;
31403 });
31404 }
31405
31406
31407 //Configure the callbacks to be called.
31408 deferred.reject.__requireJsBuild = true;
31409
31410 //Use a wrapping function so can check for errors.
31411 function includeFinished(value) {
31412 //If a sync build environment, check for errors here, instead of
31413 //in the then callback below, since some errors, like two IDs pointed
31414 //to same URL but only one anon ID will leave the loader in an
31415 //unresolved state since a setTimeout cannot be used to check for
31416 //timeout.
31417 var hasError = false;
31418 if (syncChecks[env.get()]) {
31419 try {
31420 build.checkForErrors(context, layer);
31421 } catch (e) {
31422 hasError = true;
31423 deferred.reject(e);
31424 }
31425 }
31426
31427 if (!hasError) {
31428 deferred.resolve(value);
31429 }
31430 }
31431 includeFinished.__requireJsBuild = true;
31432
31433 //Figure out module layer dependencies by calling require to do the work.
31434 require(include, includeFinished, deferred.reject);
31435
31436 // If a sync env, then with the "two IDs to same anon module path"
31437 // issue, the require never completes, need to check for errors
31438 // here.
31439 if (syncChecks[env.get()]) {
31440 build.checkForErrors(context, layer);
31441 }
31442
31443 return deferred.promise.then(function () {
31444 //Reset config
31445 if (module.override && baseLoaderConfig) {
31446 require(copyConfig(baseLoaderConfig));
31447 }
31448
31449 build.checkForErrors(context, layer);
31450
31451 return layer;
31452 });
31453 };
31454
31455 build.checkForErrors = function (context, layer) {
31456 //Check to see if it all loaded. If not, then throw, and give
31457 //a message on what is left.
31458 var id, prop, mod, idParts, pluginId, pluginResources,
31459 errMessage = '',
31460 failedPluginMap = {},
31461 failedPluginIds = [],
31462 errIds = [],
31463 errUrlMap = {},
31464 errUrlConflicts = {},
31465 hasErrUrl = false,
31466 hasUndefined = false,
31467 defined = context.defined,
31468 registry = context.registry;
31469
31470 function populateErrUrlMap(id, errUrl, skipNew) {
31471 // Loader plugins do not have an errUrl, so skip them.
31472 if (!errUrl) {
31473 return;
31474 }
31475
31476 if (!skipNew) {
31477 errIds.push(id);
31478 }
31479
31480 if (errUrlMap[errUrl]) {
31481 hasErrUrl = true;
31482 //This error module has the same URL as another
31483 //error module, could be misconfiguration.
31484 if (!errUrlConflicts[errUrl]) {
31485 errUrlConflicts[errUrl] = [];
31486 //Store the original module that had the same URL.
31487 errUrlConflicts[errUrl].push(errUrlMap[errUrl]);
31488 }
31489 errUrlConflicts[errUrl].push(id);
31490 } else if (!skipNew) {
31491 errUrlMap[errUrl] = id;
31492 }
31493 }
31494
31495 for (id in registry) {
31496 if (hasProp(registry, id) && id.indexOf('_@r') !== 0) {
31497 hasUndefined = true;
31498 mod = getOwn(registry, id);
31499 idParts = id.split('!');
31500 pluginId = idParts[0];
31501
31502 if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) {
31503 populateErrUrlMap(id, mod.map.url);
31504 }
31505
31506 //Look for plugins that did not call load()
31507 //But skip plugin IDs that were already inlined and called
31508 //define() with a name.
31509 if (!hasProp(layer.modulesWithNames, id) && idParts.length > 1) {
31510 if (falseProp(failedPluginMap, pluginId)) {
31511 failedPluginIds.push(pluginId);
31512 }
31513 pluginResources = failedPluginMap[pluginId];
31514 if (!pluginResources) {
31515 pluginResources = failedPluginMap[pluginId] = [];
31516 }
31517 pluginResources.push(id + (mod.error ? ': ' + mod.error : ''));
31518 }
31519 }
31520 }
31521
31522 // If have some modules that are not defined/stuck in the registry,
31523 // then check defined modules for URL overlap.
31524 if (hasUndefined) {
31525 for (id in defined) {
31526 if (hasProp(defined, id) && id.indexOf('!') === -1) {
31527 populateErrUrlMap(id, require.toUrl(id) + '.js', true);
31528 }
31529 }
31530 }
31531
31532 if (errIds.length || failedPluginIds.length) {
31533 if (failedPluginIds.length) {
31534 errMessage += 'Loader plugin' +
31535 (failedPluginIds.length === 1 ? '' : 's') +
31536 ' did not call ' +
31537 'the load callback in the build:\n' +
31538 failedPluginIds.map(function (pluginId) {
31539 var pluginResources = failedPluginMap[pluginId];
31540 return pluginId + ':\n ' + pluginResources.join('\n ');
31541 }).join('\n') + '\n';
31542 }
31543 errMessage += 'Module loading did not complete for: ' + errIds.join(', ');
31544
31545 if (hasErrUrl) {
31546 errMessage += '\nThe following modules share the same URL. This ' +
31547 'could be a misconfiguration if that URL only has ' +
31548 'one anonymous module in it:';
31549 for (prop in errUrlConflicts) {
31550 if (hasProp(errUrlConflicts, prop)) {
31551 errMessage += '\n' + prop + ': ' +
31552 errUrlConflicts[prop].join(', ');
31553 }
31554 }
31555 }
31556 throw new Error(errMessage);
31557 }
31558 };
31559
31560 build.createOverrideConfig = function (config, override) {
31561 var cfg = copyConfig(config),
31562 oride = copyConfig(override);
31563
31564 lang.eachProp(oride, function (value, prop) {
31565 if (hasProp(build.objProps, prop)) {
31566 //An object property, merge keys. Start a new object
31567 //so that source object in config does not get modified.
31568 cfg[prop] = {};
31569 lang.mixin(cfg[prop], config[prop], true);
31570 lang.mixin(cfg[prop], override[prop], true);
31571 } else {
31572 cfg[prop] = override[prop];
31573 }
31574 });
31575
31576 return cfg;
31577 };
31578
31579 /**
31580 * Uses the module build config object to create an flattened version
31581 * of the module, with deep dependencies included.
31582 *
31583 * @param {Object} module the module object from the build config info.
31584 *
31585 * @param {Object} layer the layer object returned from build.traceDependencies.
31586 *
31587 * @param {Object} the build config object.
31588 *
31589 * @returns {Object} with two properties: "text", the text of the flattened
31590 * module, and "buildText", a string of text representing which files were
31591 * included in the flattened module text.
31592 */
31593 build.flattenModule = function (module, layer, config) {
31594 var fileContents, sourceMapGenerator,
31595 sourceMapBase,
31596 buildFileContents = '';
31597
31598 return prim().start(function () {
31599 var reqIndex, currContents, fileForSourceMap,
31600 moduleName, shim, packageName,
31601 parts, builder, writeApi,
31602 namespace, namespaceWithDot, stubModulesByName,
31603 context = layer.context,
31604 onLayerEnds = [],
31605 onLayerEndAdded = {},
31606 pkgsMainMap = {};
31607
31608 //Use override settings, particularly for pragmas
31609 //Do this before the var readings since it reads config values.
31610 if (module.override) {
31611 config = build.createOverrideConfig(config, module.override);
31612 }
31613
31614 namespace = config.namespace || '';
31615 namespaceWithDot = namespace ? namespace + '.' : '';
31616 stubModulesByName = (module.stubModules && module.stubModules._byName) || {};
31617
31618 //Start build output for the module.
31619 module.onCompleteData = {
31620 name: module.name,
31621 path: (config.dir ? module._buildPath.replace(config.dir, "") : module._buildPath),
31622 included: []
31623 };
31624
31625 buildFileContents += "\n" +
31626 module.onCompleteData.path +
31627 "\n----------------\n";
31628
31629 //If there was an existing file with require in it, hoist to the top.
31630 if (layer.existingRequireUrl) {
31631 reqIndex = layer.buildFilePaths.indexOf(layer.existingRequireUrl);
31632 if (reqIndex !== -1) {
31633 layer.buildFilePaths.splice(reqIndex, 1);
31634 layer.buildFilePaths.unshift(layer.existingRequireUrl);
31635 }
31636 }
31637
31638 if (config.generateSourceMaps) {
31639 sourceMapBase = config.dir || config.baseUrl;
31640 if (module._buildPath === 'FUNCTION') {
31641 fileForSourceMap = (module.name || module.include[0] || 'FUNCTION') + '.build.js';
31642 } else if (config.out) {
31643 fileForSourceMap = module._buildPath.split('/').pop();
31644 } else {
31645 fileForSourceMap = module._buildPath.replace(sourceMapBase, '');
31646 }
31647 sourceMapGenerator = new SourceMapGenerator({
31648 file: fileForSourceMap
31649 });
31650 }
31651
31652 //Create a reverse lookup for packages main module IDs to their package
31653 //names, useful for knowing when to write out define() package main ID
31654 //adapters.
31655 lang.eachProp(layer.context.config.pkgs, function(value, prop) {
31656 pkgsMainMap[value] = prop;
31657 });
31658
31659 //Write the built module to disk, and build up the build output.
31660 fileContents = config.wrap ? config.wrap.start : "";
31661 return prim.serial(layer.buildFilePaths.map(function (path) {
31662 return function () {
31663 var lineCount,
31664 singleContents = '';
31665
31666 moduleName = layer.buildFileToModule[path];
31667
31668 //If the moduleName is a package main, then hold on to the
31669 //packageName in case an adapter needs to be written.
31670 packageName = getOwn(pkgsMainMap, moduleName);
31671
31672 return prim().start(function () {
31673 //Figure out if the module is a result of a build plugin, and if so,
31674 //then delegate to that plugin.
31675 parts = context.makeModuleMap(moduleName);
31676 builder = parts.prefix && getOwn(context.defined, parts.prefix);
31677 if (builder) {
31678 if (builder.onLayerEnd && falseProp(onLayerEndAdded, parts.prefix)) {
31679 onLayerEnds.push(builder);
31680 onLayerEndAdded[parts.prefix] = true;
31681 }
31682
31683 if (builder.write) {
31684 writeApi = function (input) {
31685 singleContents += "\n" + addSemiColon(input, config);
31686 if (config.onBuildWrite) {
31687 singleContents = config.onBuildWrite(moduleName, path, singleContents);
31688 }
31689 };
31690 writeApi.asModule = function (moduleName, input) {
31691 singleContents += "\n" +
31692 addSemiColon(build.toTransport(namespace, moduleName, path, input, layer, {
31693 useSourceUrl: layer.context.config.useSourceUrl
31694 }), config);
31695 if (config.onBuildWrite) {
31696 singleContents = config.onBuildWrite(moduleName, path, singleContents);
31697 }
31698 };
31699 builder.write(parts.prefix, parts.name, writeApi);
31700 }
31701 return;
31702 } else {
31703 return prim().start(function () {
31704 if (hasProp(stubModulesByName, moduleName)) {
31705 //Just want to insert a simple module definition instead
31706 //of the source module. Useful for plugins that inline
31707 //all their resources.
31708 if (hasProp(layer.context.plugins, moduleName)) {
31709 //Slightly different content for plugins, to indicate
31710 //that dynamic loading will not work.
31711 return 'define({load: function(id){throw new Error("Dynamic load not allowed: " + id);}});';
31712 } else {
31713 return 'define({});';
31714 }
31715 } else {
31716 return require._cacheReadAsync(path);
31717 }
31718 }).then(function (text) {
31719 var hasPackageName;
31720
31721 currContents = text;
31722
31723 if (config.cjsTranslate &&
31724 (!config.shim || !lang.hasProp(config.shim, moduleName))) {
31725 currContents = commonJs.convert(path, currContents);
31726 }
31727
31728 if (config.onBuildRead) {
31729 currContents = config.onBuildRead(moduleName, path, currContents);
31730 }
31731
31732 if (packageName) {
31733 hasPackageName = (packageName === parse.getNamedDefine(currContents));
31734 }
31735
31736 if (namespace) {
31737 currContents = pragma.namespace(currContents, namespace);
31738 }
31739
31740 currContents = build.toTransport(namespace, moduleName, path, currContents, layer, {
31741 useSourceUrl: config.useSourceUrl
31742 });
31743
31744 if (packageName && !hasPackageName) {
31745 currContents = addSemiColon(currContents, config) + '\n';
31746 currContents += namespaceWithDot + "define('" +
31747 packageName + "', ['" + moduleName +
31748 "'], function (main) { return main; });\n";
31749 }
31750
31751 if (config.onBuildWrite) {
31752 currContents = config.onBuildWrite(moduleName, path, currContents);
31753 }
31754
31755 //Semicolon is for files that are not well formed when
31756 //concatenated with other content.
31757 singleContents += addSemiColon(currContents, config);
31758 });
31759 }
31760 }).then(function () {
31761 var refPath, pluginId, resourcePath, shimDeps,
31762 sourceMapPath, sourceMapLineNumber,
31763 shortPath = path.replace(config.dir, "");
31764
31765 module.onCompleteData.included.push(shortPath);
31766 buildFileContents += shortPath + "\n";
31767
31768 //Some files may not have declared a require module, and if so,
31769 //put in a placeholder call so the require does not try to load them
31770 //after the module is processed.
31771 //If we have a name, but no defined module, then add in the placeholder.
31772 if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) {
31773 shim = config.shim && (getOwn(config.shim, moduleName) || (packageName && getOwn(config.shim, packageName)));
31774 if (shim) {
31775 shimDeps = lang.isArray(shim) ? shim : shim.deps;
31776 if (config.wrapShim) {
31777
31778 singleContents = '(function(root) {\n' +
31779 namespaceWithDot + 'define("' + moduleName + '", ' +
31780 (shimDeps && shimDeps.length ?
31781 build.makeJsArrayString(shimDeps) + ', ' : '[], ') +
31782 'function() {\n' +
31783 ' return (function() {\n' +
31784 singleContents +
31785 // Start with a \n in case last line is a comment
31786 // in the singleContents, like a sourceURL comment.
31787 '\n' + (shim.exportsFn ? shim.exportsFn() : '') +
31788 '\n' +
31789 ' }).apply(root, arguments);\n' +
31790 '});\n' +
31791 '}(this));\n';
31792 } else {
31793 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", ' +
31794 (shimDeps && shimDeps.length ?
31795 build.makeJsArrayString(shimDeps) + ', ' : '') +
31796 (shim.exportsFn ? shim.exportsFn() : 'function(){}') +
31797 ');\n';
31798 }
31799 } else {
31800 singleContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", function(){});\n';
31801 }
31802 }
31803
31804 //Add line break at end of file, instead of at beginning,
31805 //so source map line numbers stay correct, but still allow
31806 //for some space separation between files in case ASI issues
31807 //for concatenation would cause an error otherwise.
31808 singleContents += '\n';
31809
31810 //Add to the source map
31811 if (sourceMapGenerator) {
31812 refPath = config.out ? config.baseUrl : module._buildPath;
31813 parts = path.split('!');
31814 if (parts.length === 1) {
31815 //Not a plugin resource, fix the path
31816 sourceMapPath = build.makeRelativeFilePath(refPath, path);
31817 } else {
31818 //Plugin resource. If it looks like just a plugin
31819 //followed by a module ID, pull off the plugin
31820 //and put it at the end of the name, otherwise
31821 //just leave it alone.
31822 pluginId = parts.shift();
31823 resourcePath = parts.join('!');
31824 if (resourceIsModuleIdRegExp.test(resourcePath)) {
31825 sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) +
31826 '!' + pluginId;
31827 } else {
31828 sourceMapPath = path;
31829 }
31830 }
31831
31832 sourceMapLineNumber = fileContents.split('\n').length - 1;
31833 lineCount = singleContents.split('\n').length;
31834 for (var i = 1; i <= lineCount; i += 1) {
31835 sourceMapGenerator.addMapping({
31836 generated: {
31837 line: sourceMapLineNumber + i,
31838 column: 0
31839 },
31840 original: {
31841 line: i,
31842 column: 0
31843 },
31844 source: sourceMapPath
31845 });
31846 }
31847
31848 //Store the content of the original in the source
31849 //map since other transforms later like minification
31850 //can mess up translating back to the original
31851 //source.
31852 sourceMapGenerator.setSourceContent(sourceMapPath, singleContents);
31853 }
31854
31855 //Add the file to the final contents
31856 fileContents += singleContents;
31857 });
31858 };
31859 })).then(function () {
31860 if (onLayerEnds.length) {
31861 onLayerEnds.forEach(function (builder) {
31862 var path;
31863 if (typeof module.out === 'string') {
31864 path = module.out;
31865 } else if (typeof module._buildPath === 'string') {
31866 path = module._buildPath;
31867 }
31868 builder.onLayerEnd(function (input) {
31869 fileContents += "\n" + addSemiColon(input, config);
31870 }, {
31871 name: module.name,
31872 path: path
31873 });
31874 });
31875 }
31876
31877 if (module.create) {
31878 //The ID is for a created layer. Write out
31879 //a module definition for it in case the
31880 //built file is used with enforceDefine
31881 //(#432)
31882 fileContents += '\n' + namespaceWithDot + 'define("' + module.name + '", function(){});\n';
31883 }
31884
31885 //Add a require at the end to kick start module execution, if that
31886 //was desired. Usually this is only specified when using small shim
31887 //loaders like almond.
31888 if (module.insertRequire) {
31889 fileContents += '\n' + namespaceWithDot + 'require(["' + module.insertRequire.join('", "') + '"]);\n';
31890 }
31891 });
31892 }).then(function () {
31893 return {
31894 text: config.wrap ?
31895 fileContents + config.wrap.end :
31896 fileContents,
31897 buildText: buildFileContents,
31898 sourceMap: sourceMapGenerator ?
31899 JSON.stringify(sourceMapGenerator.toJSON(), null, ' ') :
31900 undefined
31901 };
31902 });
31903 };
31904
31905 //Converts an JS array of strings to a string representation.
31906 //Not using JSON.stringify() for Rhino's sake.
31907 build.makeJsArrayString = function (ary) {
31908 return '["' + ary.map(function (item) {
31909 //Escape any double quotes, backslashes
31910 return lang.jsEscape(item);
31911 }).join('","') + '"]';
31912 };
31913
31914 build.toTransport = function (namespace, moduleName, path, contents, layer, options) {
31915 var baseUrl = layer && layer.context.config.baseUrl;
31916
31917 function onFound(info) {
31918 //Only mark this module as having a name if not a named module,
31919 //or if a named module and the name matches expectations.
31920 if (layer && (info.needsId || info.foundId === moduleName)) {
31921 layer.modulesWithNames[moduleName] = true;
31922 }
31923 }
31924
31925 //Convert path to be a local one to the baseUrl, useful for
31926 //useSourceUrl.
31927 if (baseUrl) {
31928 path = path.replace(baseUrl, '');
31929 }
31930
31931 return transform.toTransport(namespace, moduleName, path, contents, onFound, options);
31932 };
31933
31934 return build;
31935});
31936
31937 }
31938
31939
31940 /**
31941 * Sets the default baseUrl for requirejs to be directory of top level
31942 * script.
31943 */
31944 function setBaseUrl(fileName) {
31945 //Use the file name's directory as the baseUrl if available.
31946 dir = fileName.replace(/\\/g, '/');
31947 if (dir.indexOf('/') !== -1) {
31948 dir = dir.split('/');
31949 dir.pop();
31950 dir = dir.join('/');
31951 //Make sure dir is JS-escaped, since it will be part of a JS string.
31952 exec("require({baseUrl: '" + dir.replace(/[\\"']/g, '\\$&') + "'});");
31953 }
31954 }
31955
31956 function createRjsApi() {
31957 //Create a method that will run the optimzer given an object
31958 //config.
31959 requirejs.optimize = function (config, callback, errback) {
31960 if (!loadedOptimizedLib) {
31961 loadLib();
31962 loadedOptimizedLib = true;
31963 }
31964
31965 //Create the function that will be called once build modules
31966 //have been loaded.
31967 var runBuild = function (build, logger, quit) {
31968 //Make sure config has a log level, and if not,
31969 //make it "silent" by default.
31970 config.logLevel = config.hasOwnProperty('logLevel') ?
31971 config.logLevel : logger.SILENT;
31972
31973 //Reset build internals first in case this is part
31974 //of a long-running server process that could have
31975 //exceptioned out in a bad state. It is only defined
31976 //after the first call though.
31977 if (requirejs._buildReset) {
31978 requirejs._buildReset();
31979 requirejs._cacheReset();
31980 }
31981
31982 function done(result) {
31983 //And clean up, in case something else triggers
31984 //a build in another pathway.
31985 if (requirejs._buildReset) {
31986 requirejs._buildReset();
31987 requirejs._cacheReset();
31988 }
31989
31990 // Ensure errors get propagated to the errback
31991 if (result instanceof Error) {
31992 throw result;
31993 }
31994
31995 return result;
31996 }
31997
31998 errback = errback || function (err) {
31999 // Using console here since logger may have
32000 // turned off error logging. Since quit is
32001 // called want to be sure a message is printed.
32002 console.log(err);
32003 quit(1);
32004 };
32005
32006 build(config).then(done, done).then(callback, errback);
32007 };
32008
32009 requirejs({
32010 context: 'build'
32011 }, ['build', 'logger', 'env!env/quit'], runBuild);
32012 };
32013
32014 requirejs.tools = {
32015 useLib: function (contextName, callback) {
32016 if (!callback) {
32017 callback = contextName;
32018 contextName = 'uselib';
32019 }
32020
32021 if (!useLibLoaded[contextName]) {
32022 loadLib();
32023 useLibLoaded[contextName] = true;
32024 }
32025
32026 var req = requirejs({
32027 context: contextName
32028 });
32029
32030 req(['build'], function () {
32031 callback(req);
32032 });
32033 }
32034 };
32035
32036 requirejs.define = define;
32037 }
32038
32039 //If in Node, and included via a require('requirejs'), just export and
32040 //THROW IT ON THE GROUND!
32041 if (env === 'node' && reqMain !== module) {
32042 setBaseUrl(path.resolve(reqMain ? reqMain.filename : '.'));
32043
32044 createRjsApi();
32045
32046 module.exports = requirejs;
32047 return;
32048 } else if (env === 'browser') {
32049 //Only option is to use the API.
32050 setBaseUrl(location.href);
32051 createRjsApi();
32052 return;
32053 } else if ((env === 'rhino' || env === 'xpconnect') &&
32054 //User sets up requirejsAsLib variable to indicate it is loaded
32055 //via load() to be used as a library.
32056 typeof requirejsAsLib !== 'undefined' && requirejsAsLib) {
32057 //This script is loaded via rhino's load() method, expose the
32058 //API and get out.
32059 setBaseUrl(fileName);
32060 createRjsApi();
32061 return;
32062 }
32063
32064 if (commandOption === 'o') {
32065 //Do the optimizer work.
32066 loadLib();
32067
32068 /**
32069 * @license Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
32070 * Available via the MIT or new BSD license.
32071 * see: http://github.com/jrburke/requirejs for details
32072 */
32073
32074/*
32075 * Create a build.js file that has the build options you want and pass that
32076 * build file to this file to do the build. See example.build.js for more information.
32077 */
32078
32079/*jslint strict: false, nomen: false */
32080/*global require: false */
32081
32082require({
32083 baseUrl: require.s.contexts._.config.baseUrl,
32084 //Use a separate context than the default context so that the
32085 //build can use the default context.
32086 context: 'build',
32087 catchError: {
32088 define: true
32089 }
32090}, ['env!env/args', 'env!env/quit', 'logger', 'build'],
32091function (args, quit, logger, build) {
32092 build(args).then(function () {}, function (err) {
32093 logger.error(err);
32094 quit(1);
32095 });
32096});
32097
32098
32099 } else if (commandOption === 'v') {
32100 console.log('r.js: ' + version +
32101 ', RequireJS: ' + this.requirejsVars.require.version +
32102 ', UglifyJS2: 2.6.1, UglifyJS: 1.3.4');
32103 } else if (commandOption === 'convert') {
32104 loadLib();
32105
32106 this.requirejsVars.require(['env!env/args', 'commonJs', 'env!env/print'],
32107 function (args, commonJs, print) {
32108
32109 var srcDir, outDir;
32110 srcDir = args[0];
32111 outDir = args[1];
32112
32113 if (!srcDir || !outDir) {
32114 print('Usage: path/to/commonjs/modules output/dir');
32115 return;
32116 }
32117
32118 commonJs.convertDir(args[0], args[1]);
32119 });
32120 } else {
32121 //Just run an app
32122
32123 //Load the bundled libraries for use in the app.
32124 if (commandOption === 'lib') {
32125 loadLib();
32126 }
32127
32128 setBaseUrl(fileName);
32129
32130 if (exists(fileName)) {
32131 exec(readFile(fileName), fileName);
32132 } else {
32133 showHelp();
32134 }
32135 }
32136
32137}((typeof console !== 'undefined' ? console : undefined),
32138 (typeof Packages !== 'undefined' || (typeof window === 'undefined' &&
32139 typeof Components !== 'undefined' && Components.interfaces) ?
32140 Array.prototype.slice.call(arguments, 0) : []),
32141 (typeof readFile !== 'undefined' ? readFile : undefined)));