pax_global_header00006660000000000000000000000064131203060660014507gustar00rootroot0000000000000052 comment=0af80eca22c57af9e945d7fe5def25b07ef6db06 UglifyJS2-2.8.29/000077500000000000000000000000001312030606600133675ustar00rootroot00000000000000UglifyJS2-2.8.29/.gitattributes000066400000000000000000000000241312030606600162560ustar00rootroot00000000000000*.js text eol=lf UglifyJS2-2.8.29/.github/000077500000000000000000000000001312030606600147275ustar00rootroot00000000000000UglifyJS2-2.8.29/.github/ISSUE_TEMPLATE.md000066400000000000000000000007201312030606600174330ustar00rootroot00000000000000- Bug report or feature request? - `uglify-js` version (`uglifyjs -V`) - JavaScript input - ideally as small as possible. - The `uglifyjs` CLI command executed or `minify()` options used. - An example of JavaScript output produced and/or the error or warning. UglifyJS2-2.8.29/.gitignore000066400000000000000000000000431312030606600153540ustar00rootroot00000000000000/node_modules/ /npm-debug.log tmp/ UglifyJS2-2.8.29/.travis.yml000066400000000000000000000002201312030606600154720ustar00rootroot00000000000000language: node_js node_js: - "0.10" - "0.12" - "4" - "6" env: - UGLIFYJS_TEST_ALL=1 matrix: fast_finish: true sudo: false UglifyJS2-2.8.29/LICENSE000066400000000000000000000025041312030606600143750ustar00rootroot00000000000000UglifyJS is released under the BSD license: Copyright 2012-2013 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. UglifyJS2-2.8.29/README.md000066400000000000000000001216731312030606600146600ustar00rootroot00000000000000UglifyJS 2 ========== [![Build Status](https://travis-ci.org/mishoo/UglifyJS2.svg)](https://travis-ci.org/mishoo/UglifyJS2) UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit. This page documents the command line utility. For [API and internals documentation see my website](http://lisperator.net/uglifyjs/). There's also an [in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox, Chrome and probably Safari). #### Note: - `uglify-js` only supports ECMAScript 5 (ES5). - Support for `const` is [present but incomplete](#support-for-const), and may not be transformed properly. - Those wishing to minify ES2015+ (ES6+) should use the `npm` package [**uglify-es**](https://github.com/mishoo/UglifyJS2/tree/harmony). Install ------- First make sure you have installed the latest version of [node.js](http://nodejs.org/) (You may need to restart your computer after this step). From NPM for use as a command line app: npm install uglify-js -g From NPM for programmatic use: npm install uglify-js Usage ----- uglifyjs [input files] [options] UglifyJS2 can take multiple input files. It's recommended that you pass the input files first, then pass the options. UglifyJS will parse input files in sequence and apply any compression options. The files are parsed in the same global scope, that is, a reference from a file to some variable/function declared in another file will be matched properly. If you want to read from STDIN instead, pass a single dash instead of input files. If you wish to pass your options before the input files, separate the two with a double dash to prevent input files being used as option arguments: uglifyjs --compress --mangle -- input.js The available options are: ``` --source-map Specify an output file where to generate source map. --source-map-root The path to the original source to be included in the source map. --source-map-url The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map. --source-map-include-sources Pass this flag if you want to include the content of source files in the source map as sourcesContent property. --source-map-inline Write base64-encoded source map to the end of js output. --in-source-map Input source map, useful if you're compressing JS that was generated from some other original code. Specify "inline" if the source map is included inline with the sources. --screw-ie8 Use this flag if you don't wish to support Internet Explorer 6/7/8. By default UglifyJS will not try to be IE-proof. --support-ie8 Use this flag to support Internet Explorer 6/7/8. Equivalent to setting `screw_ie8: false` in `minify()` for `compress`, `mangle` and `output` options. --expr Parse a single expression, rather than a program (for parsing JSON) -p, --prefix Skip prefix for original filenames that appear in source maps. For example -p 3 will drop 3 directories from file names and ensure they are relative paths. You can also specify -p relative, which will make UglifyJS figure out itself the relative paths between original sources, the source map and the output file. -o, --output Output file (default STDOUT). -b, --beautify Beautify output/specify output options. -m, --mangle Mangle names/pass mangler options. -r, --reserved Reserved names to exclude from mangling. -c, --compress Enable compressor/pass compressor options, e.g. `-c 'if_return=false,pure_funcs=["Math.pow","console.log"]'` Use `-c` with no argument to enable default compression options. -d, --define Global definitions -e, --enclose Embed everything in a big function, with a configurable parameter/argument list. --comments Preserve copyright comments in the output. By default this works like Google Closure, keeping JSDoc-style comments that contain "@license" or "@preserve". You can optionally pass one of the following arguments to this flag: - "all" to keep all comments - a valid JS RegExp like `/foo/` or `/^!/` to keep only matching comments. Note that currently not *all* comments can be kept when compression is on, because of dead code removal or cascading statements into sequences. --preamble Preamble to prepend to the output. You can use this to insert a comment, for example for licensing information. This will not be parsed, but the source map will adjust for its presence. --stats Display operations run time on STDERR. --acorn Use Acorn for parsing. --spidermonkey Assume input files are SpiderMonkey AST format (as JSON). --self Build itself (UglifyJS2) as a library (implies --wrap=UglifyJS --export-all) --wrap Embed everything in a big function, making the “exports” and “global” variables available. You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser. --export-all Only used when --wrap, this tells UglifyJS to add code to automatically export all globals. --lint Display some scope warnings -v, --verbose Verbose -V, --version Print version number and exit. --noerr Don't throw an error for unknown options in -c, -b or -m. --bare-returns Allow return outside of functions. Useful when minifying CommonJS modules and Userscripts that may be anonymous function wrapped (IIFE) by the .user.js engine `caller`. --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name. --reserved-file File containing reserved names --reserve-domprops Make (most?) DOM properties reserved for --mangle-props --mangle-props Mangle property names (default `0`). Set to `true` or `1` to mangle all property names. Set to `unquoted` or `2` to only mangle unquoted property names. Mode `2` also enables the `keep_quoted_props` beautifier option to preserve the quotes around property names and disables the `properties` compressor option to prevent rewriting quoted properties with dot notation. You can override these by setting them explicitly on the command line. --mangle-regex Only mangle property names matching the regex --name-cache File to hold mangled names mappings --pure-funcs Functions that can be safely removed if their return value is not used, e.g. `--pure-funcs Math.floor console.info` (requires `--compress`) ``` Specify `--output` (`-o`) to declare the output file. Otherwise the output goes to STDOUT. ## Source map options UglifyJS2 can generate a source map file, which is highly useful for debugging your compressed JavaScript. To get a source map, pass `--source-map output.js.map` (full path to the file where you want the source map dumped). Additionally you might need `--source-map-root` to pass the URL where the original files can be found. In case you are passing full paths to input files to UglifyJS, you can use `--prefix` (`-p`) to specify the number of directories to drop from the path prefix when declaring files in the source map. For example: uglifyjs /home/doe/work/foo/src/js/file1.js \ /home/doe/work/foo/src/js/file2.js \ -o foo.min.js \ --source-map foo.min.js.map \ --source-map-root http://foo.com/src \ -p 5 -c -m The above will compress and mangle `file1.js` and `file2.js`, will drop the output in `foo.min.js` and the source map in `foo.min.js.map`. The source mapping will refer to `http://foo.com/src/js/file1.js` and `http://foo.com/src/js/file2.js` (in fact it will list `http://foo.com/src` as the source map root, and the original files as `js/file1.js` and `js/file2.js`). ### Composed source map When you're compressing JS code that was output by a compiler such as CoffeeScript, mapping to the JS code won't be too helpful. Instead, you'd like to map back to the original code (i.e. CoffeeScript). UglifyJS has an option to take an input source map. Assuming you have a mapping from CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript → compressed JS by mapping every token in the compiled JS to its original location. To use this feature you need to pass `--in-source-map /path/to/input/source.map` or `--in-source-map inline` if the source map is included inline with the sources. Normally the input source map should also point to the file containing the generated JS, so if that's correct you can omit input files from the command line. ## Mangler options To enable the mangler you need to pass `--mangle` (`-m`). The following (comma-separated) options are supported: - `toplevel` — mangle names declared in the toplevel scope (disabled by default). - `eval` — mangle names visible in scopes where `eval` or `with` are used (disabled by default). When mangling is enabled but you want to prevent certain names from being mangled, you can declare those names with `--reserved` (`-r`) — pass a comma-separated list of names. For example: uglifyjs ... -m -r '$,require,exports' to prevent the `require`, `exports` and `$` names from being changed. ### Mangling property names (`--mangle-props`) **Note:** this will probably break your code. Mangling property names is a separate step, different from variable name mangling. Pass `--mangle-props`. It will mangle all properties that are seen in some object literal, or that are assigned to. For example: ```js var x = { foo: 1 }; x.bar = 2; x["baz"] = 3; x[condition ? "moo" : "boo"] = 4; console.log(x.something()); ``` In the above code, `foo`, `bar`, `baz`, `moo` and `boo` will be replaced with single characters, while `something()` will be left as is. In order for this to be of any use, we should avoid mangling standard JS names. For instance, if your code would contain `x.length = 10`, then `length` becomes a candidate for mangling and it will be mangled throughout the code, regardless if it's being used as part of your own objects or accessing an array's length. To avoid that, you can use `--reserved-file` to pass a filename that should contain the names to be excluded from mangling. This file can be used both for excluding variable names and property names. It could look like this, for example: ```js { "vars": [ "define", "require", ... ], "props": [ "length", "prototype", ... ] } ``` `--reserved-file` can be an array of file names (either a single comma-separated argument, or you can pass multiple `--reserved-file` arguments) — in this case it will exclude names from all those files. A default exclusion file is provided in `tools/domprops.json` which should cover most standard JS and DOM properties defined in various browsers. Pass `--reserve-domprops` to read that in. You can also use a regular expression to define which property names should be mangled. For example, `--mangle-regex="/^_/"` will only mangle property names that start with an underscore. When you compress multiple files using this option, in order for them to work together in the end we need to ensure somehow that one property gets mangled to the same name in all of them. For this, pass `--name-cache filename.json` and UglifyJS will maintain these mappings in a file which can then be reused. It should be initially empty. Example: ``` rm -f /tmp/cache.json # start fresh uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js ``` Now, `part1.js` and `part2.js` will be consistent with each other in terms of mangled property names. Using the name cache is not necessary if you compress all your files in a single call to UglifyJS. #### Mangling unquoted names (`--mangle-props=unquoted` or `--mangle-props=2`) Using quoted property name (`o["foo"]`) reserves the property name (`foo`) so that it is not mangled throughout the entire script even when used in an unquoted style (`o.foo`). Example: ``` $ echo 'var o={"foo":1, bar:3}; o.foo += o.bar; console.log(o.foo);' | uglifyjs --mangle-props=2 -mc var o={"foo":1,a:3};o.foo+=o.a,console.log(o.foo); ``` #### Debugging property name mangling You can also pass `--mangle-props-debug` in order to mangle property names without completely obscuring them. For example the property `o.foo` would mangle to `o._$foo$_` with this option. This allows property mangling of a large codebase while still being able to debug the code and identify where mangling is breaking things. You can also pass a custom suffix using `--mangle-props-debug=XYZ`. This would then mangle `o.foo` to `o._$foo$XYZ_`. You can change this each time you compile a script to identify how a property got mangled. One technique is to pass a random number on every compile to simulate mangling changing with different inputs (e.g. as you update the input script with new properties), and to help identify mistakes like writing mangled keys to storage. ## Compressor options You need to pass `--compress` (`-c`) to enable the compressor. Optionally you can pass a comma-separated list of options. Options are in the form `foo=bar`, or just `foo` (the latter implies a boolean option that you want to set `true`; it's effectively a shortcut for `foo=true`). - `sequences` (default: true) -- join consecutive simple statements using the comma operator. May be set to a positive integer to specify the maximum number of consecutive comma sequences that will be generated. If this option is set to `true` then the default `sequences` limit is `200`. Set option to `false` or `0` to disable. The smallest `sequences` length is `2`. A `sequences` value of `1` is grandfathered to be equivalent to `true` and as such means `200`. On rare occasions the default sequences limit leads to very slow compress times in which case a value of `20` or less is recommended. - `properties` -- rewrite property access using the dot notation, for example `foo["bar"] → foo.bar` - `dead_code` -- remove unreachable code - `drop_debugger` -- remove `debugger;` statements - `unsafe` (default: false) -- apply "unsafe" transformations (discussion below) - `unsafe_comps` (default: false) -- Reverse `<` and `<=` to `>` and `>=` to allow improved compression. This might be unsafe when an at least one of two operands is an object with computed values due the use of methods like `get`, or `valueOf`. This could cause change in execution order after operands in the comparison are switching. Compression only works if both `comparisons` and `unsafe_comps` are both set to true. - `unsafe_math` (default: false) -- optimize numerical expressions like `2 * x * 3` into `6 * x`, which may give imprecise floating point results. - `unsafe_proto` (default: false) -- optimize expressions like `Array.prototype.slice.call(a)` into `[].slice.call(a)` - `unsafe_regexp` (default: false) -- enable substitutions of variables with `RegExp` values the same way as if they are constants. - `conditionals` -- apply optimizations for `if`-s and conditional expressions - `comparisons` -- apply certain optimizations to binary nodes, for example: `!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc. - `evaluate` -- attempt to evaluate constant expressions - `booleans` -- various optimizations for boolean context, for example `!!a ? b : c → a ? b : c` - `loops` -- optimizations for `do`, `while` and `for` loops when we can statically determine the condition - `unused` -- drop unreferenced functions and variables (simple direct variable assignments do not count as references unless set to `"keep_assign"`) - `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`) in the toplevel scope (`false` by default, `true` to drop both unreferenced functions and variables) - `top_retain` -- prevent specific toplevel functions and variables from `unused` removal (can be array, comma-separated, RegExp or function. Implies `toplevel`) - `hoist_funs` -- hoist function declarations - `hoist_vars` (default: false) -- hoist `var` declarations (this is `false` by default because it seems to increase the size of the output in general) - `if_return` -- optimizations for if/return and if/continue - `join_vars` -- join consecutive `var` statements - `cascade` -- small optimization for sequences, transform `x, x` into `x` and `x = something(), x` into `x = something()` - `collapse_vars` -- Collapse single-use `var` and `const` definitions when possible. - `reduce_vars` -- Improve optimization on variables assigned with and used as constant values. - `warnings` -- display warnings when dropping unreachable code or unused declarations etc. - `negate_iife` -- negate "Immediately-Called Function Expressions" where the return value is discarded, to avoid the parens that the code generator would insert. - `pure_getters` -- the default is `false`. If you pass `true` for this, UglifyJS will assume that object property access (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. Specify `"strict"` to treat `foo.bar` as side-effect-free only when `foo` is certain to not throw, i.e. not `null` or `undefined`. - `pure_funcs` -- default `null`. You can pass an array of names and UglifyJS will assume that those functions do not produce side effects. DANGER: will not check if the name is redefined in scope. An example case here, for instance `var q = Math.floor(a/b)`. If variable `q` is not used elsewhere, UglifyJS will drop it, but will still keep the `Math.floor(a/b)`, not knowing what it does. You can pass `pure_funcs: [ 'Math.floor' ]` to let it know that this function won't produce any side effect, in which case the whole statement would get discarded. The current implementation adds some overhead (compression will be slower). - `drop_console` -- default `false`. Pass `true` to discard calls to `console.*` functions. If you wish to drop a specific function call such as `console.info` and/or retain side effects from function arguments after dropping the function call then use `pure_funcs` instead. - `expression` -- default `false`. Pass `true` to preserve completion values from terminal statements without `return`, e.g. in bookmarklets. - `keep_fargs` -- default `true`. Prevents the compressor from discarding unused function arguments. You need this for code which relies on `Function.length`. - `keep_fnames` -- default `false`. Pass `true` to prevent the compressor from discarding function names. Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle). - `passes` -- default `1`. Number of times to run compress with a maximum of 3. In some cases more than one pass leads to further compressed code. Keep in mind more passes will take more time. - `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from being compressed into `1/0`, which may cause performance issues on Chrome. - `side_effects` -- default `true`. Pass `false` to disable potentially dropping functions marked as "pure". A function call is marked as "pure" if a comment annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For example: `/*@__PURE__*/foo();` ### The `unsafe` option It enables some transformations that *might* break code logic in certain contrived cases, but should be fine for most code. You might want to try it on your own code, it should reduce the minified size. Here's what happens when this flag is on: - `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[ 1, 2, 3 ]` - `new Object()` → `{}` - `String(exp)` or `exp.toString()` → `"" + exp` - `new Object/RegExp/Function/Error/Array (...)` → we discard the `new` - `typeof foo == "undefined"` → `foo === void 0` - `void 0` → `undefined` (if there is a variable named "undefined" in scope; we do it because the variable name will be mangled, typically reduced to a single character) ### Conditional compilation You can use the `--define` (`-d`) switch in order to declare global variables that UglifyJS will assume to be constants (unless defined in scope). For example if you pass `--define DEBUG=false` then, coupled with dead code removal UglifyJS will discard the following from the output: ```javascript if (DEBUG) { console.log("debug stuff"); } ``` You can specify nested constants in the form of `--define env.DEBUG=false`. UglifyJS will warn about the condition being always false and about dropping unreachable code; for now there is no option to turn off only this specific warning, you can pass `warnings=false` to turn off *all* warnings. Another way of doing that is to declare your globals as constants in a separate file and include it into the build. For example you can have a `build/defines.js` file with the following: ```javascript const DEBUG = false; const PRODUCTION = true; // etc. ``` and build your code like this: uglifyjs build/defines.js js/foo.js js/bar.js... -c UglifyJS will notice the constants and, since they cannot be altered, it will evaluate references to them to the value itself and drop unreachable code as usual. The build will contain the `const` declarations if you use them. If you are targeting < ES6 environments which does not support `const`, using `var` with `reduce_vars` (enabled by default) should suffice. #### Conditional compilation, API You can also use conditional compilation via the programmatic API. With the difference that the property name is `global_defs` and is a compressor property: ```js uglifyJS.minify([ "input.js"], { compress: { dead_code: true, global_defs: { DEBUG: false } } }); ``` ## Beautifier options The code generator tries to output shortest code possible by default. In case you want beautified output, pass `--beautify` (`-b`). Optionally you can pass additional arguments that control the code output: - `beautify` (default `true`) -- whether to actually beautify the output. Passing `-b` will set this to true, but you might need to pass `-b` even when you want to generate minified code, in order to specify additional arguments, so you can use `-b beautify=false` to override it. - `indent-level` (default 4) - `indent-start` (default 0) -- prefix all lines by that many spaces - `quote-keys` (default `false`) -- pass `true` to quote all keys in literal objects - `space-colon` (default `true`) -- insert a space after the colon signs - `ascii-only` (default `false`) -- escape Unicode characters in strings and regexps (affects directives with non-ascii characters becoming invalid) - `inline-script` (default `false`) -- escape the slash in occurrences of ` 0) { print_error("WARN: Ignoring input files since --self was passed"); } files = UglifyJS.FILES; if (!ARGS.wrap) ARGS.wrap = "UglifyJS"; } var ORIG_MAP = ARGS.in_source_map; if (ORIG_MAP && ORIG_MAP != "inline") { ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP)); if (files.length == 0) { print_error("INFO: Using file from the input source map: " + ORIG_MAP.file); files = [ ORIG_MAP.file ]; } } if (files.length == 0) { files = [ "-" ]; } if (ORIG_MAP == "inline") { if (files.length > 1) { print_error("ERROR: Inline source map only works with singular input"); process.exit(1); } if (ARGS.acorn || ARGS.spidermonkey) { print_error("ERROR: Inline source map only works with built-in parser"); process.exit(1); } } if (files.indexOf("-") >= 0 && ARGS.source_map) { print_error("ERROR: Source map doesn't work with input from STDIN"); process.exit(1); } if (files.filter(function(el){ return el == "-" }).length > 1) { print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)"); process.exit(1); } var STATS = {}; var TOPLEVEL = null; var P_RELATIVE = ARGS.p && ARGS.p == "relative"; var SOURCES_CONTENT = {}; var index = 0; !function cb() { if (index == files.length) return done(); var file = files[index++]; read_whole_file(file, function (err, code) { if (err) { print_error("ERROR: can't read file: " + file); process.exit(1); } if (ORIG_MAP == "inline") { ORIG_MAP = read_source_map(code); } if (ARGS.p != null) { if (P_RELATIVE) { file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/'); } else { var p = parseInt(ARGS.p, 10); if (!isNaN(p)) { file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/"); } } } SOURCES_CONTENT[file] = code; time_it("parse", function(){ if (ARGS.spidermonkey) { var program = JSON.parse(code); if (!TOPLEVEL) TOPLEVEL = program; else TOPLEVEL.body = TOPLEVEL.body.concat(program.body); } else if (ARGS.acorn) { TOPLEVEL = acorn.parse(code, { locations : true, sourceFile : file, program : TOPLEVEL }); } else { try { TOPLEVEL = UglifyJS.parse(code, { filename : file, toplevel : TOPLEVEL, expression : ARGS.expr, bare_returns : ARGS.bare_returns, }); } catch(ex) { if (ex instanceof UglifyJS.JS_Parse_Error) { print_error("Parse error at " + file + ":" + ex.line + "," + ex.col); var col = ex.col; var lines = code.split(/\r?\n/); var line = lines[ex.line - 1]; if (!line && !col) { line = lines[ex.line - 2]; col = line.length; } if (line) { if (col > 40) { line = line.slice(col - 40); col = 40; } print_error(line.slice(0, 80)); print_error(line.slice(0, col).replace(/\S/g, " ") + "^"); } print_error(ex.stack); process.exit(1); } throw ex; } }; }); cb(); }); }(); function done() { var OUTPUT_FILE = ARGS.o; var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({ file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE, root: ARGS.source_map_root || ORIG_MAP && ORIG_MAP.sourceRoot, orig: ORIG_MAP, }) : null; OUTPUT_OPTIONS.source_map = SOURCE_MAP; try { var output = UglifyJS.OutputStream(OUTPUT_OPTIONS); var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS); } catch(ex) { if (ex instanceof UglifyJS.DefaultsError) { print_error(ex.message); print_error("Supported options:"); print_error(sys.inspect(ex.defs)); process.exit(1); } } if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){ TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL); }); if (ARGS.wrap != null) { TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all); } if (ARGS.enclose != null) { var arg_parameter_list = ARGS.enclose; if (arg_parameter_list === true) { arg_parameter_list = []; } else if (!(arg_parameter_list instanceof Array)) { arg_parameter_list = [arg_parameter_list]; } TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list); } if (ARGS.mangle_props || ARGS.name_cache) (function(){ var reserved = RESERVED ? RESERVED.props : null; var cache = readNameCache("props"); var regex; try { regex = ARGS.mangle_regex ? extractRegex(ARGS.mangle_regex) : null; } catch (e) { print_error("ERROR: Invalid --mangle-regex: " + e.message); process.exit(1); } TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, { reserved : reserved, cache : cache, only_cache : !ARGS.mangle_props, regex : regex, ignore_quoted : ARGS.mangle_props == 2, debug : typeof ARGS.mangle_props_debug === "undefined" ? false : ARGS.mangle_props_debug }); writeNameCache("props", cache); })(); var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint var TL_CACHE = readNameCache("vars"); if (MANGLE) MANGLE.cache = TL_CACHE; if (SCOPE_IS_NEEDED) { time_it("scope", function(){ TOPLEVEL.figure_out_scope(MANGLE || { screw_ie8: screw_ie8, cache: TL_CACHE }); if (ARGS.lint) { TOPLEVEL.scope_warnings(); } }); } if (COMPRESS) { time_it("squeeze", function(){ TOPLEVEL = compressor.compress(TOPLEVEL); }); } if (SCOPE_IS_NEEDED) { time_it("scope", function(){ TOPLEVEL.figure_out_scope(MANGLE || { screw_ie8: screw_ie8, cache: TL_CACHE }); if (MANGLE && !TL_CACHE) { TOPLEVEL.compute_char_frequency(MANGLE); } }); } if (MANGLE) time_it("mangle", function(){ TOPLEVEL.mangle_names(MANGLE); }); writeNameCache("vars", TL_CACHE); if (ARGS.source_map_include_sources) { for (var file in SOURCES_CONTENT) { if (SOURCES_CONTENT.hasOwnProperty(file)) { SOURCE_MAP.get().setSourceContent(file, SOURCES_CONTENT[file]); } } } if (ARGS.dump_spidermonkey_ast) { print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2)); } else { time_it("generate", function(){ TOPLEVEL.print(output); }); output = output.get(); if (SOURCE_MAP) { if (ARGS.source_map_inline) { var base64_string = new Buffer(SOURCE_MAP.toString()).toString('base64'); output += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + base64_string; } else { fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8"); var source_map_url = ARGS.source_map_url || ( P_RELATIVE ? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map) : ARGS.source_map ); output += "\n//# sourceMappingURL=" + source_map_url; } } if (OUTPUT_FILE) { fs.writeFileSync(OUTPUT_FILE, output, "utf8"); } else { print(output); } } if (ARGS.stats) { print_error(UglifyJS.string_template("Timing information (compressed {count} files):", { count: files.length })); for (var i in STATS) if (STATS.hasOwnProperty(i)) { print_error(UglifyJS.string_template("- {name}: {time}s", { name: i, time: (STATS[i] / 1000).toFixed(3) })); } } } /* -----[ functions ]----- */ function normalize(o) { for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) { o[i.replace(/-/g, "_")] = o[i]; delete o[i]; } } function getOptions(flag, constants) { var x = ARGS[flag]; if (x == null || x === false) return null; var ret = {}; if (x !== "") { if (Array.isArray(x)) x = x.map(function (v) { return "(" + v + ")"; }).join(", "); var ast; try { ast = UglifyJS.parse(x, { cli: true, expression: true }); } catch(ex) { if (ex instanceof UglifyJS.JS_Parse_Error) { print_error("Error parsing arguments for flag `" + flag + "': " + x); process.exit(1); } } ast.walk(new UglifyJS.TreeWalker(function(node){ if (node instanceof UglifyJS.AST_Seq) return; // descend if (node instanceof UglifyJS.AST_Assign) { var name = node.left.print_to_string().replace(/-/g, "_"); var value = node.right; if (constants) value = new Function("return (" + value.print_to_string() + ")")(); ret[name] = value; return true; // no descend } if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) { var name = node.print_to_string().replace(/-/g, "_"); ret[name] = true; return true; // no descend } print_error(node.TYPE) print_error("Error parsing arguments for flag `" + flag + "': " + x); process.exit(1); })); } return ret; } function read_whole_file(filename, cb) { if (filename == "-") { var chunks = []; process.stdin.setEncoding('utf-8'); process.stdin.on('data', function (chunk) { chunks.push(chunk); }).on('end', function () { cb(null, chunks.join("")); }); process.openStdin(); } else { fs.readFile(filename, "utf-8", cb); } } function read_source_map(code) { var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); if (!match) { print_error("WARN: inline source map not found"); return null; } return JSON.parse(new Buffer(match[2], "base64")); } function time_it(name, cont) { var t1 = new Date().getTime(); var ret = cont(); if (ARGS.stats) { var spent = new Date().getTime() - t1; if (STATS[name]) STATS[name] += spent; else STATS[name] = spent; } return ret; } function print_error(msg) { console.error("%s", msg); } function print(txt) { console.log("%s", txt); } UglifyJS2-2.8.29/lib/000077500000000000000000000000001312030606600141355ustar00rootroot00000000000000UglifyJS2-2.8.29/lib/ast.js000066400000000000000000001041101312030606600152570ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; function DEFNODE(type, props, methods, base) { if (arguments.length < 4) base = AST_Node; if (!props) props = []; else props = props.split(/\s+/); var self_props = props; if (base && base.PROPS) props = props.concat(base.PROPS); var code = "return function AST_" + type + "(props){ if (props) { "; for (var i = props.length; --i >= 0;) { code += "this." + props[i] + " = props." + props[i] + ";"; } var proto = base && new base; if (proto && proto.initialize || (methods && methods.initialize)) code += "this.initialize();"; code += "}}"; var ctor = new Function(code)(); if (proto) { ctor.prototype = proto; ctor.BASE = base; } if (base) base.SUBCLASSES.push(ctor); ctor.prototype.CTOR = ctor; ctor.PROPS = props || null; ctor.SELF_PROPS = self_props; ctor.SUBCLASSES = []; if (type) { ctor.prototype.TYPE = ctor.TYPE = type; } if (methods) for (i in methods) if (HOP(methods, i)) { if (/^\$/.test(i)) { ctor[i.substr(1)] = methods[i]; } else { ctor.prototype[i] = methods[i]; } } ctor.DEFMETHOD = function(name, method) { this.prototype[name] = method; }; if (typeof exports !== "undefined") { exports["AST_" + type] = ctor; } return ctor; }; var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", { }, null); var AST_Node = DEFNODE("Node", "start end", { _clone: function(deep) { if (deep) { var self = this.clone(); return self.transform(new TreeTransformer(function(node) { if (node !== self) { return node.clone(true); } })); } return new this.CTOR(this); }, clone: function(deep) { return this._clone(deep); }, $documentation: "Base class of all AST nodes", $propdoc: { start: "[AST_Token] The first token of this node", end: "[AST_Token] The last token of this node" }, _walk: function(visitor) { return visitor._visit(this); }, walk: function(visitor) { return this._walk(visitor); // not sure the indirection will be any help } }, null); AST_Node.warn_function = null; AST_Node.warn = function(txt, props) { if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props)); }; /* -----[ statements ]----- */ var AST_Statement = DEFNODE("Statement", null, { $documentation: "Base class of all statements", }); var AST_Debugger = DEFNODE("Debugger", null, { $documentation: "Represents a debugger statement", }, AST_Statement); var AST_Directive = DEFNODE("Directive", "value scope quote", { $documentation: "Represents a directive, like \"use strict\";", $propdoc: { value: "[string] The value of this directive as a plain string (it's not an AST_String!)", scope: "[AST_Scope/S] The scope that this directive affects", quote: "[string] the original quote character" }, }, AST_Statement); var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", $propdoc: { body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.body._walk(visitor); }); } }, AST_Statement); function walk_body(node, visitor) { var body = node.body; if (body instanceof AST_Statement) { body._walk(visitor); } else for (var i = 0, len = body.length; i < len; i++) { body[i]._walk(visitor); } }; var AST_Block = DEFNODE("Block", "body", { $documentation: "A body of statements (usually bracketed)", $propdoc: { body: "[AST_Statement*] an array of statements" }, _walk: function(visitor) { return visitor._visit(this, function(){ walk_body(this, visitor); }); } }, AST_Statement); var AST_BlockStatement = DEFNODE("BlockStatement", null, { $documentation: "A block statement", }, AST_Block); var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { $documentation: "The empty statement (empty block or simply a semicolon)", _walk: function(visitor) { return visitor._visit(this); } }, AST_Statement); var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", $propdoc: { body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.body._walk(visitor); }); } }, AST_Statement); var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { $documentation: "Statement with a label", $propdoc: { label: "[AST_Label] a label definition" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.label._walk(visitor); this.body._walk(visitor); }); }, clone: function(deep) { var node = this._clone(deep); if (deep) { var label = node.label; var def = this.label; node.walk(new TreeWalker(function(node) { if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) { node.label.thedef = label; label.references.push(node); } })); } return node; } }, AST_StatementWithBody); var AST_IterationStatement = DEFNODE("IterationStatement", null, { $documentation: "Internal class. All loops inherit from it." }, AST_StatementWithBody); var AST_DWLoop = DEFNODE("DWLoop", "condition", { $documentation: "Base class for do/while statements", $propdoc: { condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" } }, AST_IterationStatement); var AST_Do = DEFNODE("Do", null, { $documentation: "A `do` statement", _walk: function(visitor) { return visitor._visit(this, function(){ this.body._walk(visitor); this.condition._walk(visitor); }); } }, AST_DWLoop); var AST_While = DEFNODE("While", null, { $documentation: "A `while` statement", _walk: function(visitor) { return visitor._visit(this, function(){ this.condition._walk(visitor); this.body._walk(visitor); }); } }, AST_DWLoop); var AST_For = DEFNODE("For", "init condition step", { $documentation: "A `for` statement", $propdoc: { init: "[AST_Node?] the `for` initialization code, or null if empty", condition: "[AST_Node?] the `for` termination clause, or null if empty", step: "[AST_Node?] the `for` update clause, or null if empty" }, _walk: function(visitor) { return visitor._visit(this, function(){ if (this.init) this.init._walk(visitor); if (this.condition) this.condition._walk(visitor); if (this.step) this.step._walk(visitor); this.body._walk(visitor); }); } }, AST_IterationStatement); var AST_ForIn = DEFNODE("ForIn", "init name object", { $documentation: "A `for ... in` statement", $propdoc: { init: "[AST_Node] the `for/in` initialization code", name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var", object: "[AST_Node] the object that we're looping through" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.init._walk(visitor); this.object._walk(visitor); this.body._walk(visitor); }); } }, AST_IterationStatement); var AST_With = DEFNODE("With", "expression", { $documentation: "A `with` statement", $propdoc: { expression: "[AST_Node] the `with` expression" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); this.body._walk(visitor); }); } }, AST_StatementWithBody); /* -----[ scope and functions ]----- */ var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { directives: "[string*/S] an array of directives declared in this scope", variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", functions: "[Object/S] like `variables`, but only lists function declarations", uses_with: "[boolean/S] tells whether this scope uses the `with` statement", uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", parent_scope: "[AST_Scope?/S] link to the parent scope", enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", cname: "[integer/S] current index for mangling variables (used internally by the mangler)", }, }, AST_Block); var AST_Toplevel = DEFNODE("Toplevel", "globals", { $documentation: "The toplevel scope", $propdoc: { globals: "[Object/S] a map of name -> SymbolDef for all undeclared names", }, wrap_enclose: function(arg_parameter_pairs) { var self = this; var args = []; var parameters = []; arg_parameter_pairs.forEach(function(pair) { var splitAt = pair.lastIndexOf(":"); args.push(pair.substr(0, splitAt)); parameters.push(pair.substr(splitAt + 1)); }); var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; wrapped_tl = parse(wrapped_tl); wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ if (node instanceof AST_Directive && node.value == "$ORIG") { return MAP.splice(self.body); } })); return wrapped_tl; }, wrap_commonjs: function(name, export_all) { var self = this; var to_export = []; if (export_all) { self.figure_out_scope(); self.walk(new TreeWalker(function(node){ if (node instanceof AST_SymbolDeclaration && node.definition().global) { if (!find_if(function(n){ return n.name == node.name }, to_export)) to_export.push(node); } })); } var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))"; wrapped_tl = parse(wrapped_tl); wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ if (node instanceof AST_Directive) { switch (node.value) { case "$ORIG": return MAP.splice(self.body); case "$EXPORTS": var body = []; to_export.forEach(function(sym){ body.push(new AST_SimpleStatement({ body: new AST_Assign({ left: new AST_Sub({ expression: new AST_SymbolRef({ name: "exports" }), property: new AST_String({ value: sym.name }), }), operator: "=", right: new AST_SymbolRef(sym), }), })); }); return MAP.splice(body); } } })); return wrapped_tl; } }, AST_Scope); var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", { $documentation: "Base class for functions", $propdoc: { name: "[AST_SymbolDeclaration?] the name of this function", argnames: "[AST_SymbolFunarg*] array of function arguments", uses_arguments: "[boolean/S] tells whether this function accesses the arguments array" }, _walk: function(visitor) { return visitor._visit(this, function(){ if (this.name) this.name._walk(visitor); var argnames = this.argnames; for (var i = 0, len = argnames.length; i < len; i++) { argnames[i]._walk(visitor); } walk_body(this, visitor); }); } }, AST_Scope); var AST_Accessor = DEFNODE("Accessor", null, { $documentation: "A setter/getter function. The `name` property is always null." }, AST_Lambda); var AST_Function = DEFNODE("Function", null, { $documentation: "A function expression" }, AST_Lambda); var AST_Defun = DEFNODE("Defun", null, { $documentation: "A function definition" }, AST_Lambda); /* -----[ JUMPS ]----- */ var AST_Jump = DEFNODE("Jump", null, { $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" }, AST_Statement); var AST_Exit = DEFNODE("Exit", "value", { $documentation: "Base class for “exits” (`return` and `throw`)", $propdoc: { value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" }, _walk: function(visitor) { return visitor._visit(this, this.value && function(){ this.value._walk(visitor); }); } }, AST_Jump); var AST_Return = DEFNODE("Return", null, { $documentation: "A `return` statement" }, AST_Exit); var AST_Throw = DEFNODE("Throw", null, { $documentation: "A `throw` statement" }, AST_Exit); var AST_LoopControl = DEFNODE("LoopControl", "label", { $documentation: "Base class for loop control statements (`break` and `continue`)", $propdoc: { label: "[AST_LabelRef?] the label, or null if none", }, _walk: function(visitor) { return visitor._visit(this, this.label && function(){ this.label._walk(visitor); }); } }, AST_Jump); var AST_Break = DEFNODE("Break", null, { $documentation: "A `break` statement" }, AST_LoopControl); var AST_Continue = DEFNODE("Continue", null, { $documentation: "A `continue` statement" }, AST_LoopControl); /* -----[ IF ]----- */ var AST_If = DEFNODE("If", "condition alternative", { $documentation: "A `if` statement", $propdoc: { condition: "[AST_Node] the `if` condition", alternative: "[AST_Statement?] the `else` part, or null if not present" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.condition._walk(visitor); this.body._walk(visitor); if (this.alternative) this.alternative._walk(visitor); }); } }, AST_StatementWithBody); /* -----[ SWITCH ]----- */ var AST_Switch = DEFNODE("Switch", "expression", { $documentation: "A `switch` statement", $propdoc: { expression: "[AST_Node] the `switch` “discriminant”" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); walk_body(this, visitor); }); } }, AST_Block); var AST_SwitchBranch = DEFNODE("SwitchBranch", null, { $documentation: "Base class for `switch` branches", }, AST_Block); var AST_Default = DEFNODE("Default", null, { $documentation: "A `default` switch branch", }, AST_SwitchBranch); var AST_Case = DEFNODE("Case", "expression", { $documentation: "A `case` switch branch", $propdoc: { expression: "[AST_Node] the `case` expression" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); walk_body(this, visitor); }); } }, AST_SwitchBranch); /* -----[ EXCEPTIONS ]----- */ var AST_Try = DEFNODE("Try", "bcatch bfinally", { $documentation: "A `try` statement", $propdoc: { bcatch: "[AST_Catch?] the catch block, or null if not present", bfinally: "[AST_Finally?] the finally block, or null if not present" }, _walk: function(visitor) { return visitor._visit(this, function(){ walk_body(this, visitor); if (this.bcatch) this.bcatch._walk(visitor); if (this.bfinally) this.bfinally._walk(visitor); }); } }, AST_Block); var AST_Catch = DEFNODE("Catch", "argname", { $documentation: "A `catch` node; only makes sense as part of a `try` statement", $propdoc: { argname: "[AST_SymbolCatch] symbol for the exception" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.argname._walk(visitor); walk_body(this, visitor); }); } }, AST_Block); var AST_Finally = DEFNODE("Finally", null, { $documentation: "A `finally` node; only makes sense as part of a `try` statement" }, AST_Block); /* -----[ VAR/CONST ]----- */ var AST_Definitions = DEFNODE("Definitions", "definitions", { $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", $propdoc: { definitions: "[AST_VarDef*] array of variable definitions" }, _walk: function(visitor) { return visitor._visit(this, function(){ var definitions = this.definitions; for (var i = 0, len = definitions.length; i < len; i++) { definitions[i]._walk(visitor); } }); } }, AST_Statement); var AST_Var = DEFNODE("Var", null, { $documentation: "A `var` statement" }, AST_Definitions); var AST_Const = DEFNODE("Const", null, { $documentation: "A `const` statement" }, AST_Definitions); var AST_VarDef = DEFNODE("VarDef", "name value", { $documentation: "A variable declaration; only appears in a AST_Definitions node", $propdoc: { name: "[AST_SymbolVar|AST_SymbolConst] name of the variable", value: "[AST_Node?] initializer, or null of there's no initializer" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.name._walk(visitor); if (this.value) this.value._walk(visitor); }); } }); /* -----[ OTHER ]----- */ var AST_Call = DEFNODE("Call", "expression args", { $documentation: "A function call expression", $propdoc: { expression: "[AST_Node] expression to invoke as function", args: "[AST_Node*] array of arguments" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); var args = this.args; for (var i = 0, len = args.length; i < len; i++) { args[i]._walk(visitor); } }); } }); var AST_New = DEFNODE("New", null, { $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" }, AST_Call); var AST_Seq = DEFNODE("Seq", "car cdr", { $documentation: "A sequence expression (two comma-separated expressions)", $propdoc: { car: "[AST_Node] first element in sequence", cdr: "[AST_Node] second element in sequence" }, $cons: function(x, y) { var seq = new AST_Seq(x); seq.car = x; seq.cdr = y; return seq; }, $from_array: function(array) { if (array.length == 0) return null; if (array.length == 1) return array[0].clone(); var list = null; for (var i = array.length; --i >= 0;) { list = AST_Seq.cons(array[i], list); } var p = list; while (p) { if (p.cdr && !p.cdr.cdr) { p.cdr = p.cdr.car; break; } p = p.cdr; } return list; }, to_array: function() { var p = this, a = []; while (p) { a.push(p.car); if (p.cdr && !(p.cdr instanceof AST_Seq)) { a.push(p.cdr); break; } p = p.cdr; } return a; }, add: function(node) { var p = this; while (p) { if (!(p.cdr instanceof AST_Seq)) { var cell = AST_Seq.cons(p.cdr, node); return p.cdr = cell; } p = p.cdr; } }, len: function() { if (this.cdr instanceof AST_Seq) { return this.cdr.len() + 1; } else { return 2; } }, _walk: function(visitor) { return visitor._visit(this, function(){ this.car._walk(visitor); if (this.cdr) this.cdr._walk(visitor); }); } }); var AST_PropAccess = DEFNODE("PropAccess", "expression property", { $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", $propdoc: { expression: "[AST_Node] the “container” expression", 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" } }); var AST_Dot = DEFNODE("Dot", null, { $documentation: "A dotted property access expression", _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); }); } }, AST_PropAccess); var AST_Sub = DEFNODE("Sub", null, { $documentation: "Index-style property access, i.e. `a[\"foo\"]`", _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); this.property._walk(visitor); }); } }, AST_PropAccess); var AST_Unary = DEFNODE("Unary", "operator expression", { $documentation: "Base class for unary expressions", $propdoc: { operator: "[string] the operator", expression: "[AST_Node] expression that this unary operator applies to" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.expression._walk(visitor); }); } }); var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" }, AST_Unary); var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { $documentation: "Unary postfix expression, i.e. `i++`" }, AST_Unary); var AST_Binary = DEFNODE("Binary", "left operator right", { $documentation: "Binary expression, i.e. `a + b`", $propdoc: { left: "[AST_Node] left-hand side expression", operator: "[string] the operator", right: "[AST_Node] right-hand side expression" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.left._walk(visitor); this.right._walk(visitor); }); } }); var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", $propdoc: { condition: "[AST_Node]", consequent: "[AST_Node]", alternative: "[AST_Node]" }, _walk: function(visitor) { return visitor._visit(this, function(){ this.condition._walk(visitor); this.consequent._walk(visitor); this.alternative._walk(visitor); }); } }); var AST_Assign = DEFNODE("Assign", null, { $documentation: "An assignment expression — `a = b + 5`", }, AST_Binary); /* -----[ LITERALS ]----- */ var AST_Array = DEFNODE("Array", "elements", { $documentation: "An array literal", $propdoc: { elements: "[AST_Node*] array of elements" }, _walk: function(visitor) { return visitor._visit(this, function(){ var elements = this.elements; for (var i = 0, len = elements.length; i < len; i++) { elements[i]._walk(visitor); } }); } }); var AST_Object = DEFNODE("Object", "properties", { $documentation: "An object literal", $propdoc: { properties: "[AST_ObjectProperty*] array of properties" }, _walk: function(visitor) { return visitor._visit(this, function(){ var properties = this.properties; for (var i = 0, len = properties.length; i < len; i++) { properties[i]._walk(visitor); } }); } }); var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { $documentation: "Base class for literal object properties", $propdoc: { key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.", value: "[AST_Node] property value. For setters and getters this is an AST_Accessor." }, _walk: function(visitor) { return visitor._visit(this, function(){ this.value._walk(visitor); }); } }); var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", { $documentation: "A key: value object property", $propdoc: { quote: "[string] the original quote character" } }, AST_ObjectProperty); var AST_ObjectSetter = DEFNODE("ObjectSetter", null, { $documentation: "An object setter property", }, AST_ObjectProperty); var AST_ObjectGetter = DEFNODE("ObjectGetter", null, { $documentation: "An object getter property", }, AST_ObjectProperty); var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { $propdoc: { name: "[string] name of this symbol", scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", thedef: "[SymbolDef/S] the definition of this symbol" }, $documentation: "Base class for all symbols", }); var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, { $documentation: "The name of a property accessor (setter/getter function)" }, AST_Symbol); var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", }, AST_Symbol); var AST_SymbolVar = DEFNODE("SymbolVar", null, { $documentation: "Symbol defining a variable", }, AST_SymbolDeclaration); var AST_SymbolConst = DEFNODE("SymbolConst", null, { $documentation: "A constant declaration" }, AST_SymbolDeclaration); var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { $documentation: "Symbol naming a function argument", }, AST_SymbolVar); var AST_SymbolDefun = DEFNODE("SymbolDefun", null, { $documentation: "Symbol defining a function", }, AST_SymbolDeclaration); var AST_SymbolLambda = DEFNODE("SymbolLambda", null, { $documentation: "Symbol naming a function expression", }, AST_SymbolDeclaration); var AST_SymbolCatch = DEFNODE("SymbolCatch", null, { $documentation: "Symbol naming the exception in catch", }, AST_SymbolDeclaration); var AST_Label = DEFNODE("Label", "references", { $documentation: "Symbol naming a label (declaration)", $propdoc: { references: "[AST_LoopControl*] a list of nodes referring to this label" }, initialize: function() { this.references = []; this.thedef = this; } }, AST_Symbol); var AST_SymbolRef = DEFNODE("SymbolRef", null, { $documentation: "Reference to some symbol (not definition/declaration)", }, AST_Symbol); var AST_LabelRef = DEFNODE("LabelRef", null, { $documentation: "Reference to a label symbol", }, AST_Symbol); var AST_This = DEFNODE("This", null, { $documentation: "The `this` symbol", }, AST_Symbol); var AST_Constant = DEFNODE("Constant", null, { $documentation: "Base class for all constants", getValue: function() { return this.value; } }); var AST_String = DEFNODE("String", "value quote", { $documentation: "A string literal", $propdoc: { value: "[string] the contents of this string", quote: "[string] the original quote character" } }, AST_Constant); var AST_Number = DEFNODE("Number", "value literal", { $documentation: "A number literal", $propdoc: { value: "[number] the numeric value", literal: "[string] numeric value as string (optional)" } }, AST_Constant); var AST_RegExp = DEFNODE("RegExp", "value", { $documentation: "A regexp literal", $propdoc: { value: "[RegExp] the actual regexp" } }, AST_Constant); var AST_Atom = DEFNODE("Atom", null, { $documentation: "Base class for atoms", }, AST_Constant); var AST_Null = DEFNODE("Null", null, { $documentation: "The `null` atom", value: null }, AST_Atom); var AST_NaN = DEFNODE("NaN", null, { $documentation: "The impossible value", value: 0/0 }, AST_Atom); var AST_Undefined = DEFNODE("Undefined", null, { $documentation: "The `undefined` value", value: (function(){}()) }, AST_Atom); var AST_Hole = DEFNODE("Hole", null, { $documentation: "A hole in an array", value: (function(){}()) }, AST_Atom); var AST_Infinity = DEFNODE("Infinity", null, { $documentation: "The `Infinity` value", value: 1/0 }, AST_Atom); var AST_Boolean = DEFNODE("Boolean", null, { $documentation: "Base class for booleans", }, AST_Atom); var AST_False = DEFNODE("False", null, { $documentation: "The `false` atom", value: false }, AST_Boolean); var AST_True = DEFNODE("True", null, { $documentation: "The `true` atom", value: true }, AST_Boolean); /* -----[ TreeWalker ]----- */ function TreeWalker(callback) { this.visit = callback; this.stack = []; this.directives = Object.create(null); }; TreeWalker.prototype = { _visit: function(node, descend) { this.push(node); var ret = this.visit(node, descend ? function(){ descend.call(node); } : noop); if (!ret && descend) { descend.call(node); } this.pop(node); return ret; }, parent: function(n) { return this.stack[this.stack.length - 2 - (n || 0)]; }, push: function (node) { if (node instanceof AST_Lambda) { this.directives = Object.create(this.directives); } else if (node instanceof AST_Directive && !this.directives[node.value]) { this.directives[node.value] = node; } this.stack.push(node); }, pop: function(node) { this.stack.pop(); if (node instanceof AST_Lambda) { this.directives = Object.getPrototypeOf(this.directives); } }, self: function() { return this.stack[this.stack.length - 1]; }, find_parent: function(type) { var stack = this.stack; for (var i = stack.length; --i >= 0;) { var x = stack[i]; if (x instanceof type) return x; } }, has_directive: function(type) { var dir = this.directives[type]; if (dir) return dir; var node = this.stack[this.stack.length - 1]; if (node instanceof AST_Scope) { for (var i = 0; i < node.body.length; ++i) { var st = node.body[i]; if (!(st instanceof AST_Directive)) break; if (st.value == type) return st; } } }, in_boolean_context: function() { var stack = this.stack; var i = stack.length, self = stack[--i]; while (i > 0) { var p = stack[--i]; if ((p instanceof AST_If && p.condition === self) || (p instanceof AST_Conditional && p.condition === self) || (p instanceof AST_DWLoop && p.condition === self) || (p instanceof AST_For && p.condition === self) || (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self)) { return true; } if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) return false; self = p; } }, loopcontrol_target: function(node) { var stack = this.stack; if (node.label) for (var i = stack.length; --i >= 0;) { var x = stack[i]; if (x instanceof AST_LabeledStatement && x.label.name == node.label.name) return x.body; } else for (var i = stack.length; --i >= 0;) { var x = stack[i]; if (x instanceof AST_IterationStatement || node instanceof AST_Break && x instanceof AST_Switch) return x; } } }; UglifyJS2-2.8.29/lib/compress.js000066400000000000000000005364371312030606600163500ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; function Compressor(options, false_by_default) { if (!(this instanceof Compressor)) return new Compressor(options, false_by_default); TreeTransformer.call(this, this.before, this.after); this.options = defaults(options, { angular : false, booleans : !false_by_default, cascade : !false_by_default, collapse_vars : !false_by_default, comparisons : !false_by_default, conditionals : !false_by_default, dead_code : !false_by_default, drop_console : false, drop_debugger : !false_by_default, evaluate : !false_by_default, expression : false, global_defs : {}, hoist_funs : !false_by_default, hoist_vars : false, if_return : !false_by_default, join_vars : !false_by_default, keep_fargs : true, keep_fnames : false, keep_infinity : false, loops : !false_by_default, negate_iife : !false_by_default, passes : 1, properties : !false_by_default, pure_getters : !false_by_default && "strict", pure_funcs : null, reduce_vars : !false_by_default, screw_ie8 : true, sequences : !false_by_default, side_effects : !false_by_default, switches : !false_by_default, top_retain : null, toplevel : !!(options && options["top_retain"]), unsafe : false, unsafe_comps : false, unsafe_math : false, unsafe_proto : false, unsafe_regexp : false, unused : !false_by_default, warnings : true, }, true); var pure_funcs = this.options["pure_funcs"]; if (typeof pure_funcs == "function") { this.pure_funcs = pure_funcs; } else { this.pure_funcs = pure_funcs ? function(node) { return pure_funcs.indexOf(node.expression.print_to_string()) < 0; } : return_true; } var top_retain = this.options["top_retain"]; if (top_retain instanceof RegExp) { this.top_retain = function(def) { return top_retain.test(def.name); }; } else if (typeof top_retain == "function") { this.top_retain = top_retain; } else if (top_retain) { if (typeof top_retain == "string") { top_retain = top_retain.split(/,/); } this.top_retain = function(def) { return top_retain.indexOf(def.name) >= 0; }; } var sequences = this.options["sequences"]; this.sequences_limit = sequences == 1 ? 200 : sequences | 0; this.warnings_produced = {}; }; Compressor.prototype = new TreeTransformer; merge(Compressor.prototype, { option: function(key) { return this.options[key] }, compress: function(node) { if (this.option("expression")) { node = node.process_expression(true); } var passes = +this.options.passes || 1; for (var pass = 0; pass < passes && pass < 3; ++pass) { if (pass > 0 || this.option("reduce_vars")) node.reset_opt_flags(this, true); node = node.transform(this); } if (this.option("expression")) { node = node.process_expression(false); } return node; }, info: function() { if (this.options.warnings == "verbose") { AST_Node.warn.apply(AST_Node, arguments); } }, warn: function(text, props) { if (this.options.warnings) { // only emit unique warnings var message = string_template(text, props); if (!(message in this.warnings_produced)) { this.warnings_produced[message] = true; AST_Node.warn.apply(AST_Node, arguments); } } }, clear_warnings: function() { this.warnings_produced = {}; }, before: function(node, descend, in_list) { if (node._squeezed) return node; var was_scope = false; if (node instanceof AST_Scope) { node = node.hoist_declarations(this); was_scope = true; } // Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize() // would call AST_Node.transform() if a different instance of AST_Node is // produced after OPT(). // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction. // Migrate and defer all children's AST_Node.transform() to below, which // will now happen after this parent AST_Node has been properly substituted // thus gives a consistent AST snapshot. descend(node, this); // Existing code relies on how AST_Node.optimize() worked, and omitting the // following replacement call would result in degraded efficiency of both // output and performance. descend(node, this); var opt = node.optimize(this); if (was_scope && opt instanceof AST_Scope) { opt.drop_unused(this); descend(opt, this); } if (opt === node) opt._squeezed = true; return opt; } }); (function(){ function OPT(node, optimizer) { node.DEFMETHOD("optimize", function(compressor){ var self = this; if (self._optimized) return self; if (compressor.has_directive("use asm")) return self; var opt = optimizer(self, compressor); opt._optimized = true; return opt; }); }; OPT(AST_Node, function(self, compressor){ return self; }); AST_Node.DEFMETHOD("equivalent_to", function(node){ return this.TYPE == node.TYPE && this.print_to_string() == node.print_to_string(); }); AST_Node.DEFMETHOD("process_expression", function(insert, compressor) { var self = this; var tt = new TreeTransformer(function(node) { if (insert && node instanceof AST_SimpleStatement) { return make_node(AST_Return, node, { value: node.body }); } if (!insert && node instanceof AST_Return) { if (compressor) { var value = node.value && node.value.drop_side_effect_free(compressor, true); return value ? make_node(AST_SimpleStatement, node, { body: value }) : make_node(AST_EmptyStatement, node); } return make_node(AST_SimpleStatement, node, { body: node.value || make_node(AST_UnaryPrefix, node, { operator: "void", expression: make_node(AST_Number, node, { value: 0 }) }) }); } if (node instanceof AST_Lambda && node !== self) { return node; } if (node instanceof AST_Block) { var index = node.body.length - 1; if (index >= 0) { node.body[index] = node.body[index].transform(tt); } } if (node instanceof AST_If) { node.body = node.body.transform(tt); if (node.alternative) { node.alternative = node.alternative.transform(tt); } } if (node instanceof AST_With) { node.body = node.body.transform(tt); } return node; }); return self.transform(tt); }); AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan){ var reduce_vars = rescan && compressor.option("reduce_vars"); var toplevel = compressor.option("toplevel"); var safe_ids = Object.create(null); var suppressor = new TreeWalker(function(node) { if (node instanceof AST_Symbol) { var d = node.definition(); if (node instanceof AST_SymbolRef) d.references.push(node); d.fixed = false; } }); var tw = new TreeWalker(function(node, descend){ node._squeezed = false; node._optimized = false; if (reduce_vars) { if (node instanceof AST_Toplevel) node.globals.each(reset_def); if (node instanceof AST_Scope) node.variables.each(reset_def); if (node instanceof AST_SymbolRef) { var d = node.definition(); d.references.push(node); if (d.fixed === undefined || !is_safe(d) || is_modified(node, 0, node.fixed_value() instanceof AST_Lambda)) { d.fixed = false; } else { var parent = tw.parent(); if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right || parent instanceof AST_Call && node !== parent.expression || parent instanceof AST_Return && node === parent.value && node.scope !== d.scope || parent instanceof AST_VarDef && node === parent.value) { d.escaped = true; } } } if (node instanceof AST_SymbolCatch) { node.definition().fixed = false; } if (node instanceof AST_VarDef) { var d = node.name.definition(); if (d.fixed == null) { if (node.value) { d.fixed = function() { return node.value; }; mark(d, false); descend(); } else { d.fixed = null; } mark(d, true); return true; } else if (node.value) { d.fixed = false; } } if (node instanceof AST_Defun) { var d = node.name.definition(); if (!toplevel && d.global || is_safe(d)) { d.fixed = false; } else { d.fixed = node; mark(d, true); } var save_ids = safe_ids; safe_ids = Object.create(null); descend(); safe_ids = save_ids; return true; } if (node instanceof AST_Function) { push(); var iife; if (!node.name && (iife = tw.parent()) instanceof AST_Call && iife.expression === node) { // Virtually turn IIFE parameters into variable definitions: // (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})() // So existing transformation rules can work on them. node.argnames.forEach(function(arg, i) { var d = arg.definition(); if (!node.uses_arguments && d.fixed === undefined) { d.fixed = function() { return iife.args[i] || make_node(AST_Undefined, iife); }; mark(d, true); } else { d.fixed = false; } }); } descend(); pop(); return true; } if (node instanceof AST_Accessor) { var save_ids = safe_ids; safe_ids = Object.create(null); descend(); safe_ids = save_ids; return true; } if (node instanceof AST_Binary && (node.operator == "&&" || node.operator == "||")) { node.left.walk(tw); push(); node.right.walk(tw); pop(); return true; } if (node instanceof AST_Conditional) { node.condition.walk(tw); push(); node.consequent.walk(tw); pop(); push(); node.alternative.walk(tw); pop(); return true; } if (node instanceof AST_If || node instanceof AST_DWLoop) { node.condition.walk(tw); push(); node.body.walk(tw); pop(); if (node.alternative) { push(); node.alternative.walk(tw); pop(); } return true; } if (node instanceof AST_LabeledStatement) { push(); node.body.walk(tw); pop(); return true; } if (node instanceof AST_For) { if (node.init) node.init.walk(tw); push(); if (node.condition) node.condition.walk(tw); node.body.walk(tw); if (node.step) node.step.walk(tw); pop(); return true; } if (node instanceof AST_ForIn) { node.init.walk(suppressor); node.object.walk(tw); push(); node.body.walk(tw); pop(); return true; } if (node instanceof AST_Try) { push(); walk_body(node, tw); pop(); if (node.bcatch) { push(); node.bcatch.walk(tw); pop(); } if (node.bfinally) node.bfinally.walk(tw); return true; } if (node instanceof AST_SwitchBranch) { push(); descend(); pop(); return true; } } }); this.walk(tw); function mark(def, safe) { safe_ids[def.id] = safe; } function is_safe(def) { if (safe_ids[def.id]) { if (def.fixed == null) { var orig = def.orig[0]; if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false; def.fixed = make_node(AST_Undefined, orig); } return true; } } function push() { safe_ids = Object.create(safe_ids); } function pop() { safe_ids = Object.getPrototypeOf(safe_ids); } function reset_def(def) { def.escaped = false; if (def.scope.uses_eval) { def.fixed = false; } else if (toplevel || !def.global || def.orig[0] instanceof AST_SymbolConst) { def.fixed = undefined; } else { def.fixed = false; } def.references = []; def.should_replace = undefined; } function is_modified(node, level, func) { var parent = tw.parent(level); if (is_lhs(node, parent) || !func && parent instanceof AST_Call && parent.expression === node) { return true; } else if (parent instanceof AST_PropAccess && parent.expression === node) { return !func && is_modified(parent, level + 1); } } }); AST_SymbolRef.DEFMETHOD("fixed_value", function() { var fixed = this.definition().fixed; if (!fixed || fixed instanceof AST_Node) return fixed; return fixed(); }); function is_reference_const(ref) { if (!(ref instanceof AST_SymbolRef)) return false; var orig = ref.definition().orig; for (var i = orig.length; --i >= 0;) { if (orig[i] instanceof AST_SymbolConst) return true; } } function find_variable(compressor, name) { var scope, i = 0; while (scope = compressor.parent(i++)) { if (scope instanceof AST_Scope) break; if (scope instanceof AST_Catch) { scope = scope.argname.definition().scope; break; } } return scope.find_variable(name); } function make_node(ctor, orig, props) { if (!props) props = {}; if (orig) { if (!props.start) props.start = orig.start; if (!props.end) props.end = orig.end; } return new ctor(props); }; function make_node_from_constant(val, orig) { switch (typeof val) { case "string": return make_node(AST_String, orig, { value: val }); case "number": if (isNaN(val)) return make_node(AST_NaN, orig); if (isFinite(val)) { return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, { operator: "-", expression: make_node(AST_Number, orig, { value: -val }) }) : make_node(AST_Number, orig, { value: val }); } return val < 0 ? make_node(AST_UnaryPrefix, orig, { operator: "-", expression: make_node(AST_Infinity, orig) }) : make_node(AST_Infinity, orig); case "boolean": return make_node(val ? AST_True : AST_False, orig); case "undefined": return make_node(AST_Undefined, orig); default: if (val === null) { return make_node(AST_Null, orig, { value: null }); } if (val instanceof RegExp) { return make_node(AST_RegExp, orig, { value: val }); } throw new Error(string_template("Can't handle constant of type: {type}", { type: typeof val })); } }; // we shouldn't compress (1,func)(something) to // func(something) because that changes the meaning of // the func (becomes lexical instead of global). function maintain_this_binding(parent, orig, val) { if (parent instanceof AST_UnaryPrefix && parent.operator == "delete" || parent instanceof AST_Call && parent.expression === orig && (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name == "eval")) { return make_node(AST_Seq, orig, { car: make_node(AST_Number, orig, { value: 0 }), cdr: val }); } return val; } function as_statement_array(thing) { if (thing === null) return []; if (thing instanceof AST_BlockStatement) return thing.body; if (thing instanceof AST_EmptyStatement) return []; if (thing instanceof AST_Statement) return [ thing ]; throw new Error("Can't convert thing to statement array"); }; function is_empty(thing) { if (thing === null) return true; if (thing instanceof AST_EmptyStatement) return true; if (thing instanceof AST_BlockStatement) return thing.body.length == 0; return false; }; function loop_body(x) { if (x instanceof AST_Switch) return x; if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) { return (x.body instanceof AST_BlockStatement ? x.body : x); } return x; }; function is_iife_call(node) { if (node instanceof AST_Call && !(node instanceof AST_New)) { return node.expression instanceof AST_Function || is_iife_call(node.expression); } return false; } function tighten_body(statements, compressor) { var CHANGED, max_iter = 10; do { CHANGED = false; if (compressor.option("angular")) { statements = process_for_angular(statements); } statements = eliminate_spurious_blocks(statements); if (compressor.option("dead_code")) { statements = eliminate_dead_code(statements, compressor); } if (compressor.option("if_return")) { statements = handle_if_return(statements, compressor); } if (compressor.sequences_limit > 0) { statements = sequencesize(statements, compressor); } if (compressor.option("join_vars")) { statements = join_consecutive_vars(statements, compressor); } if (compressor.option("collapse_vars")) { statements = collapse_single_use_vars(statements, compressor); } } while (CHANGED && max_iter-- > 0); return statements; function collapse_single_use_vars(statements, compressor) { // Iterate statements backwards looking for a statement with a var/const // declaration immediately preceding it. Grab the rightmost var definition // and if it has exactly one reference then attempt to replace its reference // in the statement with the var value and then erase the var definition. var self = compressor.self(); var var_defs_removed = false; var toplevel = compressor.option("toplevel"); for (var stat_index = statements.length; --stat_index >= 0;) { var stat = statements[stat_index]; if (stat instanceof AST_Definitions) continue; // Process child blocks of statement if present. [stat, stat.body, stat.alternative, stat.bcatch, stat.bfinally].forEach(function(node) { node && node.body && collapse_single_use_vars(node.body, compressor); }); // The variable definition must precede a statement. if (stat_index <= 0) break; var prev_stat_index = stat_index - 1; var prev_stat = statements[prev_stat_index]; if (!(prev_stat instanceof AST_Definitions)) continue; var var_defs = prev_stat.definitions; if (var_defs == null) continue; var var_names_seen = {}; var side_effects_encountered = false; var lvalues_encountered = false; var lvalues = {}; // Scan variable definitions from right to left. for (var var_defs_index = var_defs.length; --var_defs_index >= 0;) { // Obtain var declaration and var name with basic sanity check. var var_decl = var_defs[var_defs_index]; if (var_decl.value == null) break; var var_name = var_decl.name.name; if (!var_name || !var_name.length) break; // Bail if we've seen a var definition of same name before. if (var_name in var_names_seen) break; var_names_seen[var_name] = true; // Only interested in cases with just one reference to the variable. var def = self.find_variable && self.find_variable(var_name); if (!def || !def.references || def.references.length !== 1 || var_name == "arguments" || (!toplevel && def.global)) { side_effects_encountered = true; continue; } var ref = def.references[0]; // Don't replace ref if eval() or with statement in scope. if (ref.scope.uses_eval || ref.scope.uses_with) break; // Constant single use vars can be replaced in any scope. if (var_decl.value.is_constant()) { var ctt = new TreeTransformer(function(node) { var parent = ctt.parent(); if (parent instanceof AST_IterationStatement && (parent.condition === node || parent.init === node)) { return node; } if (node === ref) return replace_var(node, parent, true); }); stat.transform(ctt); continue; } // Restrict var replacement to constants if side effects encountered. if (side_effects_encountered |= lvalues_encountered) continue; var value_has_side_effects = var_decl.value.has_side_effects(compressor); // Non-constant single use vars can only be replaced in same scope. if (ref.scope !== self) { side_effects_encountered |= value_has_side_effects; continue; } // Detect lvalues in var value. var tw = new TreeWalker(function(node){ if (node instanceof AST_SymbolRef && is_lvalue(node, tw.parent())) { lvalues[node.name] = lvalues_encountered = true; } }); var_decl.value.walk(tw); // Replace the non-constant single use var in statement if side effect free. var unwind = false; var tt = new TreeTransformer( function preorder(node) { if (unwind) return node; var parent = tt.parent(); if (node instanceof AST_Lambda || node instanceof AST_Try || node instanceof AST_With || node instanceof AST_Case || node instanceof AST_IterationStatement || (parent instanceof AST_If && node !== parent.condition) || (parent instanceof AST_Conditional && node !== parent.condition) || (node instanceof AST_SymbolRef && value_has_side_effects && !are_references_in_scope(node.definition(), self)) || (parent instanceof AST_Binary && (parent.operator == "&&" || parent.operator == "||") && node === parent.right) || (parent instanceof AST_Switch && node !== parent.expression)) { return side_effects_encountered = unwind = true, node; } function are_references_in_scope(def, scope) { if (def.orig.length === 1 && def.orig[0] instanceof AST_SymbolDefun) return true; if (def.scope !== scope) return false; var refs = def.references; for (var i = 0, len = refs.length; i < len; i++) { if (refs[i].scope !== scope) return false; } return true; } }, function postorder(node) { if (unwind) return node; if (node === ref) return unwind = true, replace_var(node, tt.parent(), false); if (side_effects_encountered |= node.has_side_effects(compressor)) return unwind = true, node; if (lvalues_encountered && node instanceof AST_SymbolRef && node.name in lvalues) { side_effects_encountered = true; return unwind = true, node; } } ); stat.transform(tt); } } // Remove extraneous empty statments in block after removing var definitions. // Leave at least one statement in `statements`. if (var_defs_removed) for (var i = statements.length; --i >= 0;) { if (statements.length > 1 && statements[i] instanceof AST_EmptyStatement) statements.splice(i, 1); } return statements; function is_lvalue(node, parent) { return node instanceof AST_SymbolRef && is_lhs(node, parent); } function replace_var(node, parent, is_constant) { if (is_lvalue(node, parent)) return node; // Remove var definition and return its value to the TreeTransformer to replace. var value = maintain_this_binding(parent, node, var_decl.value); var_decl.value = null; var_defs.splice(var_defs_index, 1); if (var_defs.length === 0) { statements[prev_stat_index] = make_node(AST_EmptyStatement, self); var_defs_removed = true; } // Further optimize statement after substitution. stat.reset_opt_flags(compressor); compressor.info("Collapsing " + (is_constant ? "constant" : "variable") + " " + var_name + " [{file}:{line},{col}]", node.start); CHANGED = true; return value; } } function process_for_angular(statements) { function has_inject(comment) { return /@ngInject/.test(comment.value); } function make_arguments_names_list(func) { return func.argnames.map(function(sym){ return make_node(AST_String, sym, { value: sym.name }); }); } function make_array(orig, elements) { return make_node(AST_Array, orig, { elements: elements }); } function make_injector(func, name) { return make_node(AST_SimpleStatement, func, { body: make_node(AST_Assign, func, { operator: "=", left: make_node(AST_Dot, name, { expression: make_node(AST_SymbolRef, name, name), property: "$inject" }), right: make_array(func, make_arguments_names_list(func)) }) }); } function check_expression(body) { if (body && body.args) { // if this is a function call check all of arguments passed body.args.forEach(function(argument, index, array) { var comments = argument.start.comments_before; // if the argument is function preceded by @ngInject if (argument instanceof AST_Lambda && comments.length && has_inject(comments[0])) { // replace the function with an array of names of its parameters and function at the end array[index] = make_array(argument, make_arguments_names_list(argument).concat(argument)); } }); // if this is chained call check previous one recursively if (body.expression && body.expression.expression) { check_expression(body.expression.expression); } } } return statements.reduce(function(a, stat){ a.push(stat); if (stat.body && stat.body.args) { check_expression(stat.body); } else { var token = stat.start; var comments = token.comments_before; if (comments && comments.length > 0) { var last = comments.pop(); if (has_inject(last)) { // case 1: defun if (stat instanceof AST_Defun) { a.push(make_injector(stat, stat.name)); } else if (stat instanceof AST_Definitions) { stat.definitions.forEach(function(def) { if (def.value && def.value instanceof AST_Lambda) { a.push(make_injector(def.value, def.name)); } }); } else { compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token); } } } } return a; }, []); } function eliminate_spurious_blocks(statements) { var seen_dirs = []; return statements.reduce(function(a, stat){ if (stat instanceof AST_BlockStatement) { CHANGED = true; a.push.apply(a, eliminate_spurious_blocks(stat.body)); } else if (stat instanceof AST_EmptyStatement) { CHANGED = true; } else if (stat instanceof AST_Directive) { if (seen_dirs.indexOf(stat.value) < 0) { a.push(stat); seen_dirs.push(stat.value); } else { CHANGED = true; } } else { a.push(stat); } return a; }, []); }; function handle_if_return(statements, compressor) { var self = compressor.self(); var multiple_if_returns = has_multiple_if_returns(statements); var in_lambda = self instanceof AST_Lambda; var ret = []; // Optimized statements, build from tail to front loop: for (var i = statements.length; --i >= 0;) { var stat = statements[i]; switch (true) { case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0): CHANGED = true; // note, ret.length is probably always zero // because we drop unreachable code before this // step. nevertheless, it's good to check. continue loop; case stat instanceof AST_If: if (stat.body instanceof AST_Return) { //--- // pretty silly case, but: // if (foo()) return; return; ==> foo(); return; if (((in_lambda && ret.length == 0) || (ret[0] instanceof AST_Return && !ret[0].value)) && !stat.body.value && !stat.alternative) { CHANGED = true; var cond = make_node(AST_SimpleStatement, stat.condition, { body: stat.condition }); ret.unshift(cond); continue loop; } //--- // if (foo()) return x; return y; ==> return foo() ? x : y; if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) { CHANGED = true; stat = stat.clone(); stat.alternative = ret[0]; ret[0] = stat.transform(compressor); continue loop; } //--- // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined; if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) { CHANGED = true; stat = stat.clone(); stat.alternative = ret[0] || make_node(AST_Return, stat, { value: null }); ret[0] = stat.transform(compressor); continue loop; } //--- // if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... } if (!stat.body.value && in_lambda) { CHANGED = true; stat = stat.clone(); stat.condition = stat.condition.negate(compressor); var body = as_statement_array(stat.alternative).concat(ret); var funs = extract_functions_from_statement_array(body); stat.body = make_node(AST_BlockStatement, stat, { body: body }); stat.alternative = null; ret = funs.concat([ stat.transform(compressor) ]); continue loop; } //--- // if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e; // // if sequences is not enabled, this can lead to an endless loop (issue #866). // however, with sequences on this helps producing slightly better output for // the example code. if (compressor.option("sequences") && i > 0 && statements[i - 1] instanceof AST_If && statements[i - 1].body instanceof AST_Return && ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement && !stat.alternative) { CHANGED = true; ret.push(make_node(AST_Return, ret[0], { value: null }).transform(compressor)); ret.unshift(stat); continue loop; } } var ab = aborts(stat.body); var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null; if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda) || (ab instanceof AST_Continue && self === loop_body(lct)) || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) { if (ab.label) { remove(ab.label.thedef.references, ab); } CHANGED = true; var body = as_statement_array(stat.body).slice(0, -1); stat = stat.clone(); stat.condition = stat.condition.negate(compressor); stat.body = make_node(AST_BlockStatement, stat, { body: as_statement_array(stat.alternative).concat(ret) }); stat.alternative = make_node(AST_BlockStatement, stat, { body: body }); ret = [ stat.transform(compressor) ]; continue loop; } var ab = aborts(stat.alternative); var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null; if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda) || (ab instanceof AST_Continue && self === loop_body(lct)) || (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) { if (ab.label) { remove(ab.label.thedef.references, ab); } CHANGED = true; stat = stat.clone(); stat.body = make_node(AST_BlockStatement, stat.body, { body: as_statement_array(stat.body).concat(ret) }); stat.alternative = make_node(AST_BlockStatement, stat.alternative, { body: as_statement_array(stat.alternative).slice(0, -1) }); ret = [ stat.transform(compressor) ]; continue loop; } ret.unshift(stat); break; default: ret.unshift(stat); break; } } return ret; function has_multiple_if_returns(statements) { var n = 0; for (var i = statements.length; --i >= 0;) { var stat = statements[i]; if (stat instanceof AST_If && stat.body instanceof AST_Return) { if (++n > 1) return true; } } return false; } }; function eliminate_dead_code(statements, compressor) { var has_quit = false; var orig = statements.length; var self = compressor.self(); statements = statements.reduce(function(a, stat){ if (has_quit) { extract_declarations_from_unreachable_code(compressor, stat, a); } else { if (stat instanceof AST_LoopControl) { var lct = compressor.loopcontrol_target(stat); if ((stat instanceof AST_Break && !(lct instanceof AST_IterationStatement) && loop_body(lct) === self) || (stat instanceof AST_Continue && loop_body(lct) === self)) { if (stat.label) { remove(stat.label.thedef.references, stat); } } else { a.push(stat); } } else { a.push(stat); } if (aborts(stat)) has_quit = true; } return a; }, []); CHANGED = statements.length != orig; return statements; }; function sequencesize(statements, compressor) { if (statements.length < 2) return statements; var seq = [], ret = []; function push_seq() { seq = AST_Seq.from_array(seq); if (seq) ret.push(make_node(AST_SimpleStatement, seq, { body: seq })); seq = []; }; statements.forEach(function(stat){ if (stat instanceof AST_SimpleStatement) { if (seqLength(seq) >= compressor.sequences_limit) push_seq(); var body = stat.body; if (seq.length > 0) body = body.drop_side_effect_free(compressor); if (body) seq.push(body); } else { push_seq(); ret.push(stat); } }); push_seq(); ret = sequencesize_2(ret, compressor); CHANGED = ret.length != statements.length; return ret; }; function seqLength(a) { for (var len = 0, i = 0; i < a.length; ++i) { var stat = a[i]; if (stat instanceof AST_Seq) { len += stat.len(); } else { len++; } } return len; }; function sequencesize_2(statements, compressor) { function cons_seq(right) { ret.pop(); var left = prev.body; if (left instanceof AST_Seq) { left.add(right); } else { left = AST_Seq.cons(left, right); } return left.transform(compressor); }; var ret = [], prev = null; statements.forEach(function(stat){ if (prev) { if (stat instanceof AST_For) { var opera = {}; try { prev.body.walk(new TreeWalker(function(node){ if (node instanceof AST_Binary && node.operator == "in") throw opera; })); if (stat.init && !(stat.init instanceof AST_Definitions)) { stat.init = cons_seq(stat.init); } else if (!stat.init) { stat.init = prev.body.drop_side_effect_free(compressor); ret.pop(); } } catch(ex) { if (ex !== opera) throw ex; } } else if (stat instanceof AST_If) { stat.condition = cons_seq(stat.condition); } else if (stat instanceof AST_With) { stat.expression = cons_seq(stat.expression); } else if (stat instanceof AST_Exit && stat.value) { stat.value = cons_seq(stat.value); } else if (stat instanceof AST_Exit) { stat.value = cons_seq(make_node(AST_Undefined, stat).transform(compressor)); } else if (stat instanceof AST_Switch) { stat.expression = cons_seq(stat.expression); } } ret.push(stat); prev = stat instanceof AST_SimpleStatement ? stat : null; }); return ret; }; function join_consecutive_vars(statements, compressor) { var prev = null; return statements.reduce(function(a, stat){ if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) { prev.definitions = prev.definitions.concat(stat.definitions); CHANGED = true; } else if (stat instanceof AST_For && prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) { CHANGED = true; a.pop(); if (stat.init) { stat.init.definitions = prev.definitions.concat(stat.init.definitions); } else { stat.init = prev; } a.push(stat); prev = stat; } else { prev = stat; a.push(stat); } return a; }, []); }; }; function extract_functions_from_statement_array(statements) { var funs = []; for (var i = statements.length - 1; i >= 0; --i) { var stat = statements[i]; if (stat instanceof AST_Defun) { statements.splice(i, 1); funs.unshift(stat); } } return funs; } function extract_declarations_from_unreachable_code(compressor, stat, target) { if (!(stat instanceof AST_Defun)) { compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start); } stat.walk(new TreeWalker(function(node){ if (node instanceof AST_Definitions) { compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start); node.remove_initializers(); target.push(node); return true; } if (node instanceof AST_Defun) { target.push(node); return true; } if (node instanceof AST_Scope) { return true; } })); }; function is_undefined(node, compressor) { return node.is_undefined || node instanceof AST_Undefined || node instanceof AST_UnaryPrefix && node.operator == "void" && !node.expression.has_side_effects(compressor); } // may_throw_on_access() // returns true if this node may be null, undefined or contain `AST_Accessor` (function(def) { AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) { var pure_getters = compressor.option("pure_getters"); return !pure_getters || this._throw_on_access(pure_getters); }); function is_strict(pure_getters) { return /strict/.test(pure_getters); } def(AST_Node, is_strict); def(AST_Null, return_true); def(AST_Undefined, return_true); def(AST_Constant, return_false); def(AST_Array, return_false); def(AST_Object, function(pure_getters) { if (!is_strict(pure_getters)) return false; for (var i = this.properties.length; --i >=0;) if (this.properties[i].value instanceof AST_Accessor) return true; return false; }); def(AST_Function, return_false); def(AST_UnaryPostfix, return_false); def(AST_UnaryPrefix, function() { return this.operator == "void"; }); def(AST_Binary, function(pure_getters) { switch (this.operator) { case "&&": return this.left._throw_on_access(pure_getters); case "||": return this.left._throw_on_access(pure_getters) && this.right._throw_on_access(pure_getters); default: return false; } }) def(AST_Assign, function(pure_getters) { return this.operator == "=" && this.right._throw_on_access(pure_getters); }) def(AST_Conditional, function(pure_getters) { return this.consequent._throw_on_access(pure_getters) || this.alternative._throw_on_access(pure_getters); }) def(AST_Seq, function(pure_getters) { return this.cdr._throw_on_access(pure_getters); }); def(AST_SymbolRef, function(pure_getters) { if (this.is_undefined) return true; if (!is_strict(pure_getters)) return false; var fixed = this.fixed_value(); return !fixed || fixed._throw_on_access(pure_getters); }); })(function(node, func) { node.DEFMETHOD("_throw_on_access", func); }); /* -----[ boolean/negation helpers ]----- */ // methods to determine whether an expression has a boolean result type (function (def){ var unary_bool = [ "!", "delete" ]; var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ]; def(AST_Node, return_false); def(AST_UnaryPrefix, function(){ return member(this.operator, unary_bool); }); def(AST_Binary, function(){ return member(this.operator, binary_bool) || ( (this.operator == "&&" || this.operator == "||") && this.left.is_boolean() && this.right.is_boolean() ); }); def(AST_Conditional, function(){ return this.consequent.is_boolean() && this.alternative.is_boolean(); }); def(AST_Assign, function(){ return this.operator == "=" && this.right.is_boolean(); }); def(AST_Seq, function(){ return this.cdr.is_boolean(); }); def(AST_True, return_true); def(AST_False, return_true); })(function(node, func){ node.DEFMETHOD("is_boolean", func); }); // methods to determine if an expression has a numeric result type (function (def){ def(AST_Node, return_false); def(AST_Number, return_true); var unary = makePredicate("+ - ~ ++ --"); def(AST_Unary, function(){ return unary(this.operator); }); var binary = makePredicate("- * / % & | ^ << >> >>>"); def(AST_Binary, function(compressor){ return binary(this.operator) || this.operator == "+" && this.left.is_number(compressor) && this.right.is_number(compressor); }); def(AST_Assign, function(compressor){ return binary(this.operator.slice(0, -1)) || this.operator == "=" && this.right.is_number(compressor); }); def(AST_Seq, function(compressor){ return this.cdr.is_number(compressor); }); def(AST_Conditional, function(compressor){ return this.consequent.is_number(compressor) && this.alternative.is_number(compressor); }); })(function(node, func){ node.DEFMETHOD("is_number", func); }); // methods to determine if an expression has a string result type (function (def){ def(AST_Node, return_false); def(AST_String, return_true); def(AST_UnaryPrefix, function(){ return this.operator == "typeof"; }); def(AST_Binary, function(compressor){ return this.operator == "+" && (this.left.is_string(compressor) || this.right.is_string(compressor)); }); def(AST_Assign, function(compressor){ return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); }); def(AST_Seq, function(compressor){ return this.cdr.is_string(compressor); }); def(AST_Conditional, function(compressor){ return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); }); })(function(node, func){ node.DEFMETHOD("is_string", func); }); var unary_side_effects = makePredicate("delete ++ --"); function is_lhs(node, parent) { if (parent instanceof AST_Unary && unary_side_effects(parent.operator)) return parent.expression; if (parent instanceof AST_Assign && parent.left === node) return node; } (function (def){ AST_Node.DEFMETHOD("resolve_defines", function(compressor) { if (!compressor.option("global_defs")) return; var def = this._find_defs(compressor, ""); if (def) { var node, parent = this, level = 0; do { node = parent; parent = compressor.parent(level++); } while (parent instanceof AST_PropAccess && parent.expression === node); if (is_lhs(node, parent)) { compressor.warn('global_defs ' + this.print_to_string() + ' redefined [{file}:{line},{col}]', this.start); } else { return def; } } }); function to_node(value, orig) { if (value instanceof AST_Node) return make_node(value.CTOR, orig, value); if (Array.isArray(value)) return make_node(AST_Array, orig, { elements: value.map(function(value) { return to_node(value, orig); }) }); if (value && typeof value == "object") { var props = []; for (var key in value) { props.push(make_node(AST_ObjectKeyVal, orig, { key: key, value: to_node(value[key], orig) })); } return make_node(AST_Object, orig, { properties: props }); } return make_node_from_constant(value, orig); } def(AST_Node, noop); def(AST_Dot, function(compressor, suffix){ return this.expression._find_defs(compressor, "." + this.property + suffix); }); def(AST_SymbolRef, function(compressor, suffix){ if (!this.global()) return; var name; var defines = compressor.option("global_defs"); if (defines && HOP(defines, (name = this.name + suffix))) { var node = to_node(defines[name], this); var top = compressor.find_parent(AST_Toplevel); node.walk(new TreeWalker(function(node) { if (node instanceof AST_SymbolRef) { node.scope = top; node.thedef = top.def_global(node); } })); return node; } }); })(function(node, func){ node.DEFMETHOD("_find_defs", func); }); function best_of_expression(ast1, ast2) { return ast1.print_to_string().length > ast2.print_to_string().length ? ast2 : ast1; } function best_of_statement(ast1, ast2) { return best_of_expression(make_node(AST_SimpleStatement, ast1, { body: ast1 }), make_node(AST_SimpleStatement, ast2, { body: ast2 })).body; } function best_of(compressor, ast1, ast2) { return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2); } // methods to evaluate a constant expression (function (def){ // If the node has been successfully reduced to a constant, // then its value is returned; otherwise the element itself // is returned. // They can be distinguished as constant value is never a // descendant of AST_Node. AST_Node.DEFMETHOD("evaluate", function(compressor){ if (!compressor.option("evaluate")) return this; try { var val = this._eval(compressor); return !val || val instanceof RegExp || typeof val != "object" ? val : this; } catch(ex) { if (ex !== def) throw ex; return this; } }); var unaryPrefix = makePredicate("! ~ - + void"); AST_Node.DEFMETHOD("is_constant", function(){ // Accomodate when compress option evaluate=false // as well as the common constant expressions !0 and -1 if (this instanceof AST_Constant) { return !(this instanceof AST_RegExp); } else { return this instanceof AST_UnaryPrefix && this.expression instanceof AST_Constant && unaryPrefix(this.operator); } }); // Obtain the constant value of an expression already known to be constant. // Result only valid iff this.is_constant() is true. AST_Node.DEFMETHOD("constant_value", function(compressor){ // Accomodate when option evaluate=false. if (this instanceof AST_Constant && !(this instanceof AST_RegExp)) { return this.value; } // Accomodate the common constant expressions !0 and -1 when option evaluate=false. if (this instanceof AST_UnaryPrefix && this.expression instanceof AST_Constant) switch (this.operator) { case "!": return !this.expression.value; case "~": return ~this.expression.value; case "-": return -this.expression.value; case "+": return +this.expression.value; default: throw new Error(string_template("Cannot evaluate unary expression {value}", { value: this.print_to_string() })); } var result = this.evaluate(compressor); if (result !== this) { return result; } throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start)); }); def(AST_Statement, function(){ throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); }); def(AST_Lambda, function(){ throw def; }); function ev(node, compressor) { if (!compressor) throw new Error("Compressor must be passed"); return node._eval(compressor); }; def(AST_Node, function(){ throw def; // not constant }); def(AST_Constant, function(){ return this.getValue(); }); def(AST_Array, function(compressor){ if (compressor.option("unsafe")) { return this.elements.map(function(element) { return ev(element, compressor); }); } throw def; }); def(AST_Object, function(compressor){ if (compressor.option("unsafe")) { var val = {}; for (var i = 0, len = this.properties.length; i < len; i++) { var prop = this.properties[i]; var key = prop.key; if (key instanceof AST_Symbol) { key = key.name; } else if (key instanceof AST_Node) { key = ev(key, compressor); } if (typeof Object.prototype[key] === 'function') { throw def; } val[key] = ev(prop.value, compressor); } return val; } throw def; }); def(AST_UnaryPrefix, function(compressor){ var e = this.expression; switch (this.operator) { case "!": return !ev(e, compressor); case "typeof": // Function would be evaluated to an array and so typeof would // incorrectly return 'object'. Hence making is a special case. if (e instanceof AST_Function) return typeof function(){}; e = ev(e, compressor); // typeof returns "object" or "function" on different platforms // so cannot evaluate reliably if (e instanceof RegExp) throw def; return typeof e; case "void": return void ev(e, compressor); case "~": return ~ev(e, compressor); case "-": return -ev(e, compressor); case "+": return +ev(e, compressor); } throw def; }); def(AST_Binary, function(c){ var left = this.left, right = this.right, result; switch (this.operator) { case "&&" : result = ev(left, c) && ev(right, c); break; case "||" : result = ev(left, c) || ev(right, c); break; case "|" : result = ev(left, c) | ev(right, c); break; case "&" : result = ev(left, c) & ev(right, c); break; case "^" : result = ev(left, c) ^ ev(right, c); break; case "+" : result = ev(left, c) + ev(right, c); break; case "*" : result = ev(left, c) * ev(right, c); break; case "/" : result = ev(left, c) / ev(right, c); break; case "%" : result = ev(left, c) % ev(right, c); break; case "-" : result = ev(left, c) - ev(right, c); break; case "<<" : result = ev(left, c) << ev(right, c); break; case ">>" : result = ev(left, c) >> ev(right, c); break; case ">>>" : result = ev(left, c) >>> ev(right, c); break; case "==" : result = ev(left, c) == ev(right, c); break; case "===" : result = ev(left, c) === ev(right, c); break; case "!=" : result = ev(left, c) != ev(right, c); break; case "!==" : result = ev(left, c) !== ev(right, c); break; case "<" : result = ev(left, c) < ev(right, c); break; case "<=" : result = ev(left, c) <= ev(right, c); break; case ">" : result = ev(left, c) > ev(right, c); break; case ">=" : result = ev(left, c) >= ev(right, c); break; default: throw def; } if (isNaN(result) && c.find_parent(AST_With)) { // leave original expression as is throw def; } return result; }); def(AST_Conditional, function(compressor){ return ev(this.condition, compressor) ? ev(this.consequent, compressor) : ev(this.alternative, compressor); }); def(AST_SymbolRef, function(compressor){ if (!compressor.option("reduce_vars") || this._evaluating) throw def; this._evaluating = true; try { var fixed = this.fixed_value(); if (!fixed) throw def; var value = ev(fixed, compressor); if (!HOP(fixed, "_eval")) fixed._eval = function() { return value; }; if (value && typeof value == "object" && this.definition().escaped) throw def; return value; } finally { this._evaluating = false; } }); def(AST_PropAccess, function(compressor){ if (compressor.option("unsafe")) { var key = this.property; if (key instanceof AST_Node) { key = ev(key, compressor); } var val = ev(this.expression, compressor); if (val && HOP(val, key)) { return val[key]; } } throw def; }); })(function(node, func){ node.DEFMETHOD("_eval", func); }); // method to negate an expression (function(def){ function basic_negation(exp) { return make_node(AST_UnaryPrefix, exp, { operator: "!", expression: exp }); } function best(orig, alt, first_in_statement) { var negated = basic_negation(orig); if (first_in_statement) { var stat = make_node(AST_SimpleStatement, alt, { body: alt }); return best_of_expression(negated, stat) === stat ? alt : negated; } return best_of_expression(negated, alt); } def(AST_Node, function(){ return basic_negation(this); }); def(AST_Statement, function(){ throw new Error("Cannot negate a statement"); }); def(AST_Function, function(){ return basic_negation(this); }); def(AST_UnaryPrefix, function(){ if (this.operator == "!") return this.expression; return basic_negation(this); }); def(AST_Seq, function(compressor){ var self = this.clone(); self.cdr = self.cdr.negate(compressor); return self; }); def(AST_Conditional, function(compressor, first_in_statement){ var self = this.clone(); self.consequent = self.consequent.negate(compressor); self.alternative = self.alternative.negate(compressor); return best(this, self, first_in_statement); }); def(AST_Binary, function(compressor, first_in_statement){ var self = this.clone(), op = this.operator; if (compressor.option("unsafe_comps")) { switch (op) { case "<=" : self.operator = ">" ; return self; case "<" : self.operator = ">=" ; return self; case ">=" : self.operator = "<" ; return self; case ">" : self.operator = "<=" ; return self; } } switch (op) { case "==" : self.operator = "!="; return self; case "!=" : self.operator = "=="; return self; case "===": self.operator = "!=="; return self; case "!==": self.operator = "==="; return self; case "&&": self.operator = "||"; self.left = self.left.negate(compressor, first_in_statement); self.right = self.right.negate(compressor); return best(this, self, first_in_statement); case "||": self.operator = "&&"; self.left = self.left.negate(compressor, first_in_statement); self.right = self.right.negate(compressor); return best(this, self, first_in_statement); } return basic_negation(this); }); })(function(node, func){ node.DEFMETHOD("negate", function(compressor, first_in_statement){ return func.call(this, compressor, first_in_statement); }); }); AST_Call.DEFMETHOD("has_pure_annotation", function(compressor) { if (!compressor.option("side_effects")) return false; if (this.pure !== undefined) return this.pure; var pure = false; var comments, last_comment; if (this.start && (comments = this.start.comments_before) && comments.length && /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) { pure = last_comment; } return this.pure = pure; }); // determine if expression has side effects (function(def){ def(AST_Node, return_true); def(AST_EmptyStatement, return_false); def(AST_Constant, return_false); def(AST_This, return_false); def(AST_Call, function(compressor){ if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return true; for (var i = this.args.length; --i >= 0;) { if (this.args[i].has_side_effects(compressor)) return true; } return false; }); function any(list, compressor) { for (var i = list.length; --i >= 0;) if (list[i].has_side_effects(compressor)) return true; return false; } def(AST_Block, function(compressor){ return any(this.body, compressor); }); def(AST_Switch, function(compressor){ return this.expression.has_side_effects(compressor) || any(this.body, compressor); }); def(AST_Case, function(compressor){ return this.expression.has_side_effects(compressor) || any(this.body, compressor); }); def(AST_Try, function(compressor){ return any(this.body, compressor) || this.bcatch && this.bcatch.has_side_effects(compressor) || this.bfinally && this.bfinally.has_side_effects(compressor); }); def(AST_If, function(compressor){ return this.condition.has_side_effects(compressor) || this.body && this.body.has_side_effects(compressor) || this.alternative && this.alternative.has_side_effects(compressor); }); def(AST_LabeledStatement, function(compressor){ return this.body.has_side_effects(compressor); }); def(AST_SimpleStatement, function(compressor){ return this.body.has_side_effects(compressor); }); def(AST_Defun, return_true); def(AST_Function, return_false); def(AST_Binary, function(compressor){ return this.left.has_side_effects(compressor) || this.right.has_side_effects(compressor); }); def(AST_Assign, return_true); def(AST_Conditional, function(compressor){ return this.condition.has_side_effects(compressor) || this.consequent.has_side_effects(compressor) || this.alternative.has_side_effects(compressor); }); def(AST_Unary, function(compressor){ return unary_side_effects(this.operator) || this.expression.has_side_effects(compressor); }); def(AST_SymbolRef, function(compressor){ return this.undeclared(); }); def(AST_Object, function(compressor){ return any(this.properties, compressor); }); def(AST_ObjectProperty, function(compressor){ return this.value.has_side_effects(compressor); }); def(AST_Array, function(compressor){ return any(this.elements, compressor); }); def(AST_Dot, function(compressor){ return this.expression.may_throw_on_access(compressor) || this.expression.has_side_effects(compressor); }); def(AST_Sub, function(compressor){ return this.expression.may_throw_on_access(compressor) || this.expression.has_side_effects(compressor) || this.property.has_side_effects(compressor); }); def(AST_Seq, function(compressor){ return this.car.has_side_effects(compressor) || this.cdr.has_side_effects(compressor); }); })(function(node, func){ node.DEFMETHOD("has_side_effects", func); }); // tell me if a statement aborts function aborts(thing) { return thing && thing.aborts(); }; (function(def){ def(AST_Statement, return_null); def(AST_Jump, return_this); function block_aborts(){ var n = this.body.length; return n > 0 && aborts(this.body[n - 1]); }; def(AST_BlockStatement, block_aborts); def(AST_SwitchBranch, block_aborts); def(AST_If, function(){ return this.alternative && aborts(this.body) && aborts(this.alternative) && this; }); })(function(node, func){ node.DEFMETHOD("aborts", func); }); /* -----[ optimizers ]----- */ OPT(AST_Directive, function(self, compressor){ if (compressor.has_directive(self.value) !== self) { return make_node(AST_EmptyStatement, self); } return self; }); OPT(AST_Debugger, function(self, compressor){ if (compressor.option("drop_debugger")) return make_node(AST_EmptyStatement, self); return self; }); OPT(AST_LabeledStatement, function(self, compressor){ if (self.body instanceof AST_Break && compressor.loopcontrol_target(self.body) === self.body) { return make_node(AST_EmptyStatement, self); } return self.label.references.length == 0 ? self.body : self; }); OPT(AST_Block, function(self, compressor){ self.body = tighten_body(self.body, compressor); return self; }); OPT(AST_BlockStatement, function(self, compressor){ self.body = tighten_body(self.body, compressor); switch (self.body.length) { case 1: return self.body[0]; case 0: return make_node(AST_EmptyStatement, self); } return self; }); AST_Scope.DEFMETHOD("drop_unused", function(compressor){ var self = this; if (compressor.has_directive("use asm")) return self; var toplevel = compressor.option("toplevel"); if (compressor.option("unused") && (!(self instanceof AST_Toplevel) || toplevel) && !self.uses_eval && !self.uses_with) { var assign_as_unused = !/keep_assign/.test(compressor.option("unused")); var drop_funcs = /funcs/.test(toplevel); var drop_vars = /vars/.test(toplevel); if (!(self instanceof AST_Toplevel) || toplevel == true) { drop_funcs = drop_vars = true; } var in_use = []; var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use if (self instanceof AST_Toplevel && compressor.top_retain) { self.variables.each(function(def) { if (compressor.top_retain(def) && !(def.id in in_use_ids)) { in_use_ids[def.id] = true; in_use.push(def); } }); } var initializations = new Dictionary(); // pass 1: find out which symbols are directly used in // this scope (not in nested scopes). var scope = this; var tw = new TreeWalker(function(node, descend){ if (node !== self) { if (node instanceof AST_Defun) { if (!drop_funcs && scope === self) { var node_def = node.name.definition(); if (!(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; in_use.push(node_def); } } initializations.add(node.name.name, node); return true; // don't go in nested scopes } if (node instanceof AST_Definitions && scope === self) { node.definitions.forEach(function(def){ if (!drop_vars) { var node_def = def.name.definition(); if (!(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; in_use.push(node_def); } } if (def.value) { initializations.add(def.name.name, def.value); if (def.value.has_side_effects(compressor)) { def.value.walk(tw); } } }); return true; } if (assign_as_unused && node instanceof AST_Assign && node.operator == "=" && node.left instanceof AST_SymbolRef && !is_reference_const(node.left) && scope === self) { node.right.walk(tw); return true; } if (node instanceof AST_SymbolRef) { var node_def = node.definition(); if (!(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; in_use.push(node_def); } return true; } if (node instanceof AST_Scope) { var save_scope = scope; scope = node; descend(); scope = save_scope; return true; } } }); self.walk(tw); // pass 2: for every used symbol we need to walk its // initialization code to figure out if it uses other // symbols (that may not be in_use). for (var i = 0; i < in_use.length; ++i) { in_use[i].orig.forEach(function(decl){ // undeclared globals will be instanceof AST_SymbolRef var init = initializations.get(decl.name); if (init) init.forEach(function(init){ var tw = new TreeWalker(function(node){ if (node instanceof AST_SymbolRef) { var node_def = node.definition(); if (!(node_def.id in in_use_ids)) { in_use_ids[node_def.id] = true; in_use.push(node_def); } } }); init.walk(tw); }); }); } // pass 3: we should drop declarations not in_use var tt = new TreeTransformer( function before(node, descend, in_list) { if (node instanceof AST_Function && node.name && !compressor.option("keep_fnames")) { var def = node.name.definition(); // any declarations with same name will overshadow // name of this anonymous function and can therefore // never be used anywhere if (!(def.id in in_use_ids) || def.orig.length > 1) node.name = null; } if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { var trim = !compressor.option("keep_fargs"); for (var a = node.argnames, i = a.length; --i >= 0;) { var sym = a[i]; if (!(sym.definition().id in in_use_ids)) { sym.__unused = true; if (trim) { a.pop(); compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", { name : sym.name, file : sym.start.file, line : sym.start.line, col : sym.start.col }); } } else { trim = false; } } } if (drop_funcs && node instanceof AST_Defun && node !== self) { if (!(node.name.definition().id in in_use_ids)) { compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", { name : node.name.name, file : node.name.start.file, line : node.name.start.line, col : node.name.start.col }); return make_node(AST_EmptyStatement, node); } return node; } if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn && tt.parent().init === node)) { var def = node.definitions.filter(function(def){ if (def.value) def.value = def.value.transform(tt); var sym = def.name.definition(); if (sym.id in in_use_ids) return true; if (sym.orig[0] instanceof AST_SymbolCatch) { def.value = def.value && def.value.drop_side_effect_free(compressor); return true; } var w = { name : def.name.name, file : def.name.start.file, line : def.name.start.line, col : def.name.start.col }; if (def.value && (def._unused_side_effects = def.value.drop_side_effect_free(compressor))) { compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w); return true; } compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", w); return false; }); // place uninitialized names at the start def = mergeSort(def, function(a, b){ if (!a.value && b.value) return -1; if (!b.value && a.value) return 1; return 0; }); // for unused names whose initialization has // side effects, we can cascade the init. code // into the next one, or next statement. var side_effects = []; for (var i = 0; i < def.length;) { var x = def[i]; if (x._unused_side_effects) { side_effects.push(x._unused_side_effects); def.splice(i, 1); } else { if (side_effects.length > 0) { side_effects.push(x.value); x.value = AST_Seq.from_array(side_effects); side_effects = []; } ++i; } } if (side_effects.length > 0) { side_effects = make_node(AST_BlockStatement, node, { body: [ make_node(AST_SimpleStatement, node, { body: AST_Seq.from_array(side_effects) }) ] }); } else { side_effects = null; } if (def.length == 0 && !side_effects) { return make_node(AST_EmptyStatement, node); } if (def.length == 0) { return in_list ? MAP.splice(side_effects.body) : side_effects; } node.definitions = def; if (side_effects) { side_effects.body.unshift(node); return in_list ? MAP.splice(side_effects.body) : side_effects; } return node; } if (drop_vars && assign_as_unused && node instanceof AST_Assign && node.operator == "=" && node.left instanceof AST_SymbolRef) { var def = node.left.definition(); if (!(def.id in in_use_ids) && self.variables.get(def.name) === def) { return maintain_this_binding(tt.parent(), node, node.right.transform(tt)); } } // certain combination of unused name + side effect leads to: // https://github.com/mishoo/UglifyJS2/issues/44 // https://github.com/mishoo/UglifyJS2/issues/1830 // that's an invalid AST. // We fix it at this stage by moving the `var` outside the `for`. if (node instanceof AST_For) { descend(node, this); if (node.init instanceof AST_BlockStatement) { var block = node.init; node.init = block.body.pop(); block.body.push(node); return in_list ? MAP.splice(block.body) : block; } else if (is_empty(node.init)) { node.init = null; } return node; } if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) { descend(node, this); if (node.body instanceof AST_BlockStatement) { var block = node.body; node.body = block.body.pop(); block.body.push(node); return in_list ? MAP.splice(block.body) : block; } return node; } if (node instanceof AST_Scope && node !== self) return node; } ); self.transform(tt); } }); AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ var self = this; if (compressor.has_directive("use asm")) return self; var hoist_funs = compressor.option("hoist_funs"); var hoist_vars = compressor.option("hoist_vars"); if (hoist_funs || hoist_vars) { var dirs = []; var hoisted = []; var vars = new Dictionary(), vars_found = 0, var_decl = 0; // let's count var_decl first, we seem to waste a lot of // space if we hoist `var` when there's only one. self.walk(new TreeWalker(function(node){ if (node instanceof AST_Scope && node !== self) return true; if (node instanceof AST_Var) { ++var_decl; return true; } })); hoist_vars = hoist_vars && var_decl > 1; var tt = new TreeTransformer( function before(node) { if (node !== self) { if (node instanceof AST_Directive) { dirs.push(node); return make_node(AST_EmptyStatement, node); } if (node instanceof AST_Defun && hoist_funs) { hoisted.push(node); return make_node(AST_EmptyStatement, node); } if (node instanceof AST_Var && hoist_vars) { node.definitions.forEach(function(def){ vars.set(def.name.name, def); ++vars_found; }); var seq = node.to_assignments(compressor); var p = tt.parent(); if (p instanceof AST_ForIn && p.init === node) { if (seq == null) { var def = node.definitions[0].name; return make_node(AST_SymbolRef, def, def); } return seq; } if (p instanceof AST_For && p.init === node) { return seq; } if (!seq) return make_node(AST_EmptyStatement, node); return make_node(AST_SimpleStatement, node, { body: seq }); } if (node instanceof AST_Scope) return node; // to avoid descending in nested scopes } } ); self = self.transform(tt); if (vars_found > 0) { // collect only vars which don't show up in self's arguments list var defs = []; vars.each(function(def, name){ if (self instanceof AST_Lambda && find_if(function(x){ return x.name == def.name.name }, self.argnames)) { vars.del(name); } else { def = def.clone(); def.value = null; defs.push(def); vars.set(name, def); } }); if (defs.length > 0) { // try to merge in assignments for (var i = 0; i < self.body.length;) { if (self.body[i] instanceof AST_SimpleStatement) { var expr = self.body[i].body, sym, assign; if (expr instanceof AST_Assign && expr.operator == "=" && (sym = expr.left) instanceof AST_Symbol && vars.has(sym.name)) { var def = vars.get(sym.name); if (def.value) break; def.value = expr.right; remove(defs, def); defs.push(def); self.body.splice(i, 1); continue; } if (expr instanceof AST_Seq && (assign = expr.car) instanceof AST_Assign && assign.operator == "=" && (sym = assign.left) instanceof AST_Symbol && vars.has(sym.name)) { var def = vars.get(sym.name); if (def.value) break; def.value = assign.right; remove(defs, def); defs.push(def); self.body[i].body = expr.cdr; continue; } } if (self.body[i] instanceof AST_EmptyStatement) { self.body.splice(i, 1); continue; } if (self.body[i] instanceof AST_BlockStatement) { var tmp = [ i, 1 ].concat(self.body[i].body); self.body.splice.apply(self.body, tmp); continue; } break; } defs = make_node(AST_Var, self, { definitions: defs }); hoisted.push(defs); }; } self.body = dirs.concat(hoisted, self.body); } return self; }); // drop_side_effect_free() // remove side-effect-free parts which only affects return value (function(def){ // Drop side-effect-free elements from an array of expressions. // Returns an array of expressions with side-effects or null // if all elements were dropped. Note: original array may be // returned if nothing changed. function trim(nodes, compressor, first_in_statement) { var ret = [], changed = false; for (var i = 0, len = nodes.length; i < len; i++) { var node = nodes[i].drop_side_effect_free(compressor, first_in_statement); changed |= node !== nodes[i]; if (node) { ret.push(node); first_in_statement = false; } } return changed ? ret.length ? ret : null : nodes; } def(AST_Node, return_this); def(AST_Constant, return_null); def(AST_This, return_null); def(AST_Call, function(compressor, first_in_statement){ if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) { if (this.expression instanceof AST_Function && (!this.expression.name || !this.expression.name.definition().references.length)) { var node = this.clone(); node.expression = node.expression.process_expression(false, compressor); return node; } return this; } if (this.pure) { compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start); this.pure.value = this.pure.value.replace(/[@#]__PURE__/g, ' '); } var args = trim(this.args, compressor, first_in_statement); return args && AST_Seq.from_array(args); }); def(AST_Accessor, return_null); def(AST_Function, return_null); def(AST_Binary, function(compressor, first_in_statement){ var right = this.right.drop_side_effect_free(compressor); if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement); switch (this.operator) { case "&&": case "||": if (right === this.right) return this; var node = this.clone(); node.right = right; return node; default: var left = this.left.drop_side_effect_free(compressor, first_in_statement); if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement); return make_node(AST_Seq, this, { car: left, cdr: right }); } }); def(AST_Assign, return_this); def(AST_Conditional, function(compressor){ var consequent = this.consequent.drop_side_effect_free(compressor); var alternative = this.alternative.drop_side_effect_free(compressor); if (consequent === this.consequent && alternative === this.alternative) return this; if (!consequent) return alternative ? make_node(AST_Binary, this, { operator: "||", left: this.condition, right: alternative }) : this.condition.drop_side_effect_free(compressor); if (!alternative) return make_node(AST_Binary, this, { operator: "&&", left: this.condition, right: consequent }); var node = this.clone(); node.consequent = consequent; node.alternative = alternative; return node; }); def(AST_Unary, function(compressor, first_in_statement){ if (unary_side_effects(this.operator)) return this; if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null; var expression = this.expression.drop_side_effect_free(compressor, first_in_statement); if (first_in_statement && this instanceof AST_UnaryPrefix && is_iife_call(expression)) { if (expression === this.expression && this.operator.length === 1) return this; return make_node(AST_UnaryPrefix, this, { operator: this.operator.length === 1 ? this.operator : "!", expression: expression }); } return expression; }); def(AST_SymbolRef, function() { return this.undeclared() ? this : null; }); def(AST_Object, function(compressor, first_in_statement){ var values = trim(this.properties, compressor, first_in_statement); return values && AST_Seq.from_array(values); }); def(AST_ObjectProperty, function(compressor, first_in_statement){ return this.value.drop_side_effect_free(compressor, first_in_statement); }); def(AST_Array, function(compressor, first_in_statement){ var values = trim(this.elements, compressor, first_in_statement); return values && AST_Seq.from_array(values); }); def(AST_Dot, function(compressor, first_in_statement){ if (this.expression.may_throw_on_access(compressor)) return this; return this.expression.drop_side_effect_free(compressor, first_in_statement); }); def(AST_Sub, function(compressor, first_in_statement){ if (this.expression.may_throw_on_access(compressor)) return this; var expression = this.expression.drop_side_effect_free(compressor, first_in_statement); if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement); var property = this.property.drop_side_effect_free(compressor); if (!property) return expression; return make_node(AST_Seq, this, { car: expression, cdr: property }); }); def(AST_Seq, function(compressor){ var cdr = this.cdr.drop_side_effect_free(compressor); if (cdr === this.cdr) return this; if (!cdr) return this.car; return make_node(AST_Seq, this, { car: this.car, cdr: cdr }); }); })(function(node, func){ node.DEFMETHOD("drop_side_effect_free", func); }); OPT(AST_SimpleStatement, function(self, compressor){ if (compressor.option("side_effects")) { var body = self.body; var node = body.drop_side_effect_free(compressor, true); if (!node) { compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start); return make_node(AST_EmptyStatement, self); } if (node !== body) { return make_node(AST_SimpleStatement, self, { body: node }); } } return self; }); OPT(AST_DWLoop, function(self, compressor){ if (!compressor.option("loops")) return self; var cond = self.condition.evaluate(compressor); if (cond !== self.condition) { if (cond) { return make_node(AST_For, self, { body: self.body }); } if (compressor.option("dead_code") && self instanceof AST_While) { var a = []; extract_declarations_from_unreachable_code(compressor, self.body, a); return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } if (self instanceof AST_Do) { var has_loop_control = false; var tw = new TreeWalker(function(node) { if (node instanceof AST_Scope || has_loop_control) return true; if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self) return has_loop_control = true; }); var parent = compressor.parent(); (parent instanceof AST_LabeledStatement ? parent : self).walk(tw); if (!has_loop_control) return self.body; } } if (self instanceof AST_While) { return make_node(AST_For, self, self).optimize(compressor); } return self; }); function if_break_in_loop(self, compressor) { function drop_it(rest) { rest = as_statement_array(rest); if (self.body instanceof AST_BlockStatement) { self.body = self.body.clone(); self.body.body = rest.concat(self.body.body.slice(1)); self.body = self.body.transform(compressor); } else { self.body = make_node(AST_BlockStatement, self.body, { body: rest }).transform(compressor); } if_break_in_loop(self, compressor); } var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; if (first instanceof AST_If) { if (first.body instanceof AST_Break && compressor.loopcontrol_target(first.body) === compressor.self()) { if (self.condition) { self.condition = make_node(AST_Binary, self.condition, { left: self.condition, operator: "&&", right: first.condition.negate(compressor), }); } else { self.condition = first.condition.negate(compressor); } drop_it(first.alternative); } else if (first.alternative instanceof AST_Break && compressor.loopcontrol_target(first.alternative) === compressor.self()) { if (self.condition) { self.condition = make_node(AST_Binary, self.condition, { left: self.condition, operator: "&&", right: first.condition, }); } else { self.condition = first.condition; } drop_it(first.body); } } }; OPT(AST_For, function(self, compressor){ if (!compressor.option("loops")) return self; if (self.condition) { var cond = self.condition.evaluate(compressor); if (compressor.option("dead_code") && !cond) { var a = []; if (self.init instanceof AST_Statement) { a.push(self.init); } else if (self.init) { a.push(make_node(AST_SimpleStatement, self.init, { body: self.init })); } extract_declarations_from_unreachable_code(compressor, self.body, a); return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } if (cond !== self.condition) { cond = make_node_from_constant(cond, self.condition).transform(compressor); self.condition = best_of_expression(cond, self.condition); } } if_break_in_loop(self, compressor); return self; }); OPT(AST_If, function(self, compressor){ if (is_empty(self.alternative)) self.alternative = null; if (!compressor.option("conditionals")) return self; // if condition can be statically determined, warn and drop // one of the blocks. note, statically determined implies // “has no side effects”; also it doesn't work for cases like // `x && true`, though it probably should. var cond = self.condition.evaluate(compressor); if (cond !== self.condition) { if (cond) { compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start); if (compressor.option("dead_code")) { var a = []; if (self.alternative) { extract_declarations_from_unreachable_code(compressor, self.alternative, a); } a.push(self.body); return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } } else { compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start); if (compressor.option("dead_code")) { var a = []; extract_declarations_from_unreachable_code(compressor, self.body, a); if (self.alternative) a.push(self.alternative); return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor); } } cond = make_node_from_constant(cond, self.condition).transform(compressor); self.condition = best_of_expression(cond, self.condition); } var negated = self.condition.negate(compressor); var self_condition_length = self.condition.print_to_string().length; var negated_length = negated.print_to_string().length; var negated_is_best = negated_length < self_condition_length; if (self.alternative && negated_is_best) { negated_is_best = false; // because we already do the switch here. // no need to swap values of self_condition_length and negated_length // here because they are only used in an equality comparison later on. self.condition = negated; var tmp = self.body; self.body = self.alternative || make_node(AST_EmptyStatement, self); self.alternative = tmp; } if (is_empty(self.body) && is_empty(self.alternative)) { return make_node(AST_SimpleStatement, self.condition, { body: self.condition.clone() }).optimize(compressor); } if (self.body instanceof AST_SimpleStatement && self.alternative instanceof AST_SimpleStatement) { return make_node(AST_SimpleStatement, self, { body: make_node(AST_Conditional, self, { condition : self.condition, consequent : self.body.body, alternative : self.alternative.body }) }).optimize(compressor); } if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { if (self_condition_length === negated_length && !negated_is_best && self.condition instanceof AST_Binary && self.condition.operator == "||") { // although the code length of self.condition and negated are the same, // negated does not require additional surrounding parentheses. // see https://github.com/mishoo/UglifyJS2/issues/979 negated_is_best = true; } if (negated_is_best) return make_node(AST_SimpleStatement, self, { body: make_node(AST_Binary, self, { operator : "||", left : negated, right : self.body.body }) }).optimize(compressor); return make_node(AST_SimpleStatement, self, { body: make_node(AST_Binary, self, { operator : "&&", left : self.condition, right : self.body.body }) }).optimize(compressor); } if (self.body instanceof AST_EmptyStatement && self.alternative instanceof AST_SimpleStatement) { return make_node(AST_SimpleStatement, self, { body: make_node(AST_Binary, self, { operator : "||", left : self.condition, right : self.alternative.body }) }).optimize(compressor); } if (self.body instanceof AST_Exit && self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) { return make_node(self.body.CTOR, self, { value: make_node(AST_Conditional, self, { condition : self.condition, consequent : self.body.value || make_node(AST_Undefined, self.body), alternative : self.alternative.value || make_node(AST_Undefined, self.alternative) }).transform(compressor) }).optimize(compressor); } if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) { self = make_node(AST_If, self, { condition: make_node(AST_Binary, self.condition, { operator: "&&", left: self.condition, right: self.body.condition }), body: self.body.body, alternative: null }); } if (aborts(self.body)) { if (self.alternative) { var alt = self.alternative; self.alternative = null; return make_node(AST_BlockStatement, self, { body: [ self, alt ] }).optimize(compressor); } } if (aborts(self.alternative)) { var body = self.body; self.body = self.alternative; self.condition = negated_is_best ? negated : self.condition.negate(compressor); self.alternative = null; return make_node(AST_BlockStatement, self, { body: [ self, body ] }).optimize(compressor); } return self; }); OPT(AST_Switch, function(self, compressor){ if (!compressor.option("switches")) return self; var branch; var value = self.expression.evaluate(compressor); if (value !== self.expression) { var expression = make_node_from_constant(value, self.expression).transform(compressor); self.expression = best_of_expression(expression, self.expression); } if (!compressor.option("dead_code")) return self; var decl = []; var body = []; var default_branch; var exact_match; for (var i = 0, len = self.body.length; i < len && !exact_match; i++) { branch = self.body[i]; if (branch instanceof AST_Default) { if (!default_branch) { default_branch = branch; } else { eliminate_branch(branch, body[body.length - 1]); } } else if (value !== self.expression) { var exp = branch.expression.evaluate(compressor); if (exp === value) { exact_match = branch; if (default_branch) { var default_index = body.indexOf(default_branch); body.splice(default_index, 1); eliminate_branch(default_branch, body[default_index - 1]); default_branch = null; } } else if (exp !== branch.expression) { eliminate_branch(branch, body[body.length - 1]); continue; } } if (aborts(branch)) { var prev = body[body.length - 1]; if (aborts(prev) && prev.body.length == branch.body.length && make_node(AST_BlockStatement, prev, prev).equivalent_to(make_node(AST_BlockStatement, branch, branch))) { prev.body = []; } } body.push(branch); } while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]); if (body.length > 0) { body[0].body = decl.concat(body[0].body); } self.body = body; while (branch = body[body.length - 1]) { var stat = branch.body[branch.body.length - 1]; if (stat instanceof AST_Break && compressor.loopcontrol_target(stat) === self) branch.body.pop(); if (branch.body.length || branch instanceof AST_Case && (default_branch || branch.expression.has_side_effects(compressor))) break; if (body.pop() === default_branch) default_branch = null; } if (body.length == 0) { return make_node(AST_BlockStatement, self, { body: decl.concat(make_node(AST_SimpleStatement, self.expression, { body: self.expression })) }).optimize(compressor); } if (body.length == 1 && (body[0] === exact_match || body[0] === default_branch)) { var has_break = false; var tw = new TreeWalker(function(node) { if (has_break || node instanceof AST_Lambda || node instanceof AST_SimpleStatement) return true; if (node instanceof AST_Break && tw.loopcontrol_target(node) === self) has_break = true; }); self.walk(tw); if (!has_break) { body = body[0].body.slice(); body.unshift(make_node(AST_SimpleStatement, self.expression, { body: self.expression })); return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); } } return self; function eliminate_branch(branch, prev) { if (prev && !aborts(prev)) { prev.body = prev.body.concat(branch.body); } else { extract_declarations_from_unreachable_code(compressor, branch, decl); } } }); OPT(AST_Try, function(self, compressor){ self.body = tighten_body(self.body, compressor); if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null; if (all(self.body, is_empty)) { var body = []; if (self.bcatch) extract_declarations_from_unreachable_code(compressor, self.bcatch, body); if (self.bfinally) body = body.concat(self.bfinally.body); return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); } return self; }); AST_Definitions.DEFMETHOD("remove_initializers", function(){ this.definitions.forEach(function(def){ def.value = null }); }); AST_Definitions.DEFMETHOD("to_assignments", function(compressor){ var reduce_vars = compressor.option("reduce_vars"); var assignments = this.definitions.reduce(function(a, def){ if (def.value) { var name = make_node(AST_SymbolRef, def.name, def.name); a.push(make_node(AST_Assign, def, { operator : "=", left : name, right : def.value })); if (reduce_vars) name.definition().fixed = false; } return a; }, []); if (assignments.length == 0) return null; return AST_Seq.from_array(assignments); }); OPT(AST_Definitions, function(self, compressor){ if (self.definitions.length == 0) return make_node(AST_EmptyStatement, self); return self; }); OPT(AST_Call, function(self, compressor){ var exp = self.expression; if (compressor.option("reduce_vars") && exp instanceof AST_SymbolRef) { var def = exp.definition(); var fixed = exp.fixed_value(); if (fixed instanceof AST_Defun) { def.fixed = fixed = make_node(AST_Function, fixed, fixed).clone(true); } if (fixed instanceof AST_Function) { exp = fixed; if (compressor.option("unused") && def.references.length == 1 && !(def.scope.uses_arguments && def.orig[0] instanceof AST_SymbolFunarg) && !def.scope.uses_eval && compressor.find_parent(AST_Scope) === def.scope) { self.expression = exp; } } } if (compressor.option("unused") && exp instanceof AST_Function && !exp.uses_arguments && !exp.uses_eval) { var pos = 0, last = 0; for (var i = 0, len = self.args.length; i < len; i++) { var trim = i >= exp.argnames.length; if (trim || exp.argnames[i].__unused) { var node = self.args[i].drop_side_effect_free(compressor); if (node) { self.args[pos++] = node; } else if (!trim) { self.args[pos++] = make_node(AST_Number, self.args[i], { value: 0 }); continue; } } else { self.args[pos++] = self.args[i]; } last = pos; } self.args.length = last; } if (compressor.option("unsafe")) { if (exp instanceof AST_SymbolRef && exp.undeclared()) { switch (exp.name) { case "Array": if (self.args.length != 1) { return make_node(AST_Array, self, { elements: self.args }).optimize(compressor); } break; case "Object": if (self.args.length == 0) { return make_node(AST_Object, self, { properties: [] }); } break; case "String": if (self.args.length == 0) return make_node(AST_String, self, { value: "" }); if (self.args.length <= 1) return make_node(AST_Binary, self, { left: self.args[0], operator: "+", right: make_node(AST_String, self, { value: "" }) }).optimize(compressor); break; case "Number": if (self.args.length == 0) return make_node(AST_Number, self, { value: 0 }); if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { expression: self.args[0], operator: "+" }).optimize(compressor); case "Boolean": if (self.args.length == 0) return make_node(AST_False, self); if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { expression: make_node(AST_UnaryPrefix, self, { expression: self.args[0], operator: "!" }), operator: "!" }).optimize(compressor); break; case "Function": // new Function() => function(){} if (self.args.length == 0) return make_node(AST_Function, self, { argnames: [], body: [] }); if (all(self.args, function(x){ return x instanceof AST_String })) { // quite a corner-case, but we can handle it: // https://github.com/mishoo/UglifyJS2/issues/203 // if the code argument is a constant, then we can minify it. try { var code = "(function(" + self.args.slice(0, -1).map(function(arg){ return arg.value; }).join(",") + "){" + self.args[self.args.length - 1].value + "})()"; var ast = parse(code); ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") }); var comp = new Compressor(compressor.options); ast = ast.transform(comp); ast.figure_out_scope({ screw_ie8: compressor.option("screw_ie8") }); ast.mangle_names(); var fun; try { ast.walk(new TreeWalker(function(node){ if (node instanceof AST_Lambda) { fun = node; throw ast; } })); } catch(ex) { if (ex !== ast) throw ex; }; if (!fun) return self; var args = fun.argnames.map(function(arg, i){ return make_node(AST_String, self.args[i], { value: arg.print_to_string() }); }); var code = OutputStream(); AST_BlockStatement.prototype._codegen.call(fun, fun, code); code = code.toString().replace(/^\{|\}$/g, ""); args.push(make_node(AST_String, self.args[self.args.length - 1], { value: code })); self.args = args; return self; } catch(ex) { if (ex instanceof JS_Parse_Error) { compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start); compressor.warn(ex.toString()); } else { console.log(ex); throw ex; } } } break; } } else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { return make_node(AST_Binary, self, { left: make_node(AST_String, self, { value: "" }), operator: "+", right: exp.expression }).optimize(compressor); } else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { var separator; if (self.args.length > 0) { separator = self.args[0].evaluate(compressor); if (separator === self.args[0]) break EXIT; // not a constant } var elements = []; var consts = []; exp.expression.elements.forEach(function(el) { var value = el.evaluate(compressor); if (value !== el) { consts.push(value); } else { if (consts.length > 0) { elements.push(make_node(AST_String, self, { value: consts.join(separator) })); consts.length = 0; } elements.push(el); } }); if (consts.length > 0) { elements.push(make_node(AST_String, self, { value: consts.join(separator) })); } if (elements.length == 0) return make_node(AST_String, self, { value: "" }); if (elements.length == 1) { if (elements[0].is_string(compressor)) { return elements[0]; } return make_node(AST_Binary, elements[0], { operator : "+", left : make_node(AST_String, self, { value: "" }), right : elements[0] }); } if (separator == "") { var first; if (elements[0].is_string(compressor) || elements[1].is_string(compressor)) { first = elements.shift(); } else { first = make_node(AST_String, self, { value: "" }); } return elements.reduce(function(prev, el){ return make_node(AST_Binary, el, { operator : "+", left : prev, right : el }); }, first).optimize(compressor); } // need this awkward cloning to not affect original element // best_of will decide which one to get through. var node = self.clone(); node.expression = node.expression.clone(); node.expression.expression = node.expression.expression.clone(); node.expression.expression.elements = elements; return best_of(compressor, self, node); } else if (exp instanceof AST_Dot && exp.expression.is_string(compressor) && exp.property == "charAt") { var arg = self.args[0]; var index = arg ? arg.evaluate(compressor) : 0; if (index !== arg) { return make_node(AST_Sub, exp, { expression: exp.expression, property: make_node_from_constant(index | 0, arg || exp) }).optimize(compressor); } } } if (exp instanceof AST_Function) { if (exp.body[0] instanceof AST_Return) { var value = exp.body[0].value; if (!value || value.is_constant()) { var args = self.args.concat(value || make_node(AST_Undefined, self)); return AST_Seq.from_array(args).transform(compressor); } } if (compressor.option("side_effects") && all(exp.body, is_empty)) { var args = self.args.concat(make_node(AST_Undefined, self)); return AST_Seq.from_array(args).transform(compressor); } } if (compressor.option("drop_console")) { if (exp instanceof AST_PropAccess) { var name = exp.expression; while (name.expression) { name = name.expression; } if (name instanceof AST_SymbolRef && name.name == "console" && name.undeclared()) { return make_node(AST_Undefined, self).optimize(compressor); } } } if (compressor.option("negate_iife") && compressor.parent() instanceof AST_SimpleStatement && is_iife_call(self)) { return self.negate(compressor, true); } return self; }); OPT(AST_New, function(self, compressor){ if (compressor.option("unsafe")) { var exp = self.expression; if (exp instanceof AST_SymbolRef && exp.undeclared()) { switch (exp.name) { case "Object": case "RegExp": case "Function": case "Error": case "Array": return make_node(AST_Call, self, self).transform(compressor); } } } return self; }); OPT(AST_Seq, function(self, compressor){ if (!compressor.option("side_effects")) return self; self.car = self.car.drop_side_effect_free(compressor, first_in_statement(compressor)); if (!self.car) return maintain_this_binding(compressor.parent(), self, self.cdr); if (compressor.option("cascade")) { var left; if (self.car instanceof AST_Assign && !self.car.left.has_side_effects(compressor)) { left = self.car.left; } else if (self.car instanceof AST_Unary && (self.car.operator == "++" || self.car.operator == "--")) { left = self.car.expression; } if (left && !(left instanceof AST_SymbolRef && (left.definition().orig[0] instanceof AST_SymbolLambda || is_reference_const(left)))) { var parent, field; var cdr = self.cdr; while (true) { if (cdr.equivalent_to(left)) { var car = self.car instanceof AST_UnaryPostfix ? make_node(AST_UnaryPrefix, self.car, { operator: self.car.operator, expression: left }) : self.car; if (parent) { parent[field] = car; return self.cdr; } return car; } if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) { if (cdr.left.is_constant()) { if (cdr.operator == "||" || cdr.operator == "&&") break; field = "right"; } else { field = "left"; } } else if (cdr instanceof AST_Call || cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) { field = "expression"; } else break; parent = cdr; cdr = cdr[field]; } } } if (is_undefined(self.cdr, compressor)) { return make_node(AST_UnaryPrefix, self, { operator : "void", expression : self.car }); } return self; }); AST_Unary.DEFMETHOD("lift_sequences", function(compressor){ if (compressor.option("sequences")) { if (this.expression instanceof AST_Seq) { var seq = this.expression; var x = seq.to_array(); var e = this.clone(); e.expression = x.pop(); x.push(e); seq = AST_Seq.from_array(x).transform(compressor); return seq; } } return this; }); OPT(AST_UnaryPostfix, function(self, compressor){ return self.lift_sequences(compressor); }); OPT(AST_UnaryPrefix, function(self, compressor){ var e = self.expression; if (self.operator == "delete" && !(e instanceof AST_SymbolRef || e instanceof AST_PropAccess || e instanceof AST_NaN || e instanceof AST_Infinity || e instanceof AST_Undefined)) { if (e instanceof AST_Seq) { e = e.to_array(); e.push(make_node(AST_True, self)); return AST_Seq.from_array(e).optimize(compressor); } return make_node(AST_Seq, self, { car: e, cdr: make_node(AST_True, self) }).optimize(compressor); } var seq = self.lift_sequences(compressor); if (seq !== self) { return seq; } if (compressor.option("side_effects") && self.operator == "void") { e = e.drop_side_effect_free(compressor); if (e) { self.expression = e; return self; } else { return make_node(AST_Undefined, self).optimize(compressor); } } if (compressor.option("booleans") && compressor.in_boolean_context()) { switch (self.operator) { case "!": if (e instanceof AST_UnaryPrefix && e.operator == "!") { // !!foo ==> foo, if we're in boolean context return e.expression; } if (e instanceof AST_Binary) { self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor))); } break; case "typeof": // typeof always returns a non-empty string, thus it's // always true in booleans compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start); return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_node(AST_Seq, self, { car: e, cdr: make_node(AST_True, self) })).optimize(compressor); } } if (self.operator == "-" && e instanceof AST_Infinity) { e = e.transform(compressor); } if (e instanceof AST_Binary && (self.operator == "+" || self.operator == "-") && (e.operator == "*" || e.operator == "/" || e.operator == "%")) { return make_node(AST_Binary, self, { operator: e.operator, left: make_node(AST_UnaryPrefix, e.left, { operator: self.operator, expression: e.left }), right: e.right }); } // avoids infinite recursion of numerals if (self.operator != "-" || !(e instanceof AST_Number || e instanceof AST_Infinity)) { var ev = self.evaluate(compressor); if (ev !== self) { ev = make_node_from_constant(ev, self).optimize(compressor); return best_of(compressor, ev, self); } } return self; }); AST_Binary.DEFMETHOD("lift_sequences", function(compressor){ if (compressor.option("sequences")) { if (this.left instanceof AST_Seq) { var seq = this.left; var x = seq.to_array(); var e = this.clone(); e.left = x.pop(); x.push(e); return AST_Seq.from_array(x).optimize(compressor); } if (this.right instanceof AST_Seq && !this.left.has_side_effects(compressor)) { var assign = this.operator == "=" && this.left instanceof AST_SymbolRef; var root = this.right.clone(); var cursor, seq = root; while (assign || !seq.car.has_side_effects(compressor)) { cursor = seq; if (seq.cdr instanceof AST_Seq) { seq = seq.cdr = seq.cdr.clone(); } else break; } if (cursor) { var e = this.clone(); e.right = cursor.cdr; cursor.cdr = e; return root.optimize(compressor); } } } return this; }); var commutativeOperators = makePredicate("== === != !== * & | ^"); OPT(AST_Binary, function(self, compressor){ function reversible() { return self.left.is_constant() || self.right.is_constant() || !self.left.has_side_effects(compressor) && !self.right.has_side_effects(compressor); } function reverse(op) { if (reversible()) { if (op) self.operator = op; var tmp = self.left; self.left = self.right; self.right = tmp; } } if (commutativeOperators(self.operator)) { if (self.right.is_constant() && !self.left.is_constant()) { // if right is a constant, whatever side effects the // left side might have could not influence the // result. hence, force switch. if (!(self.left instanceof AST_Binary && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { reverse(); } } } self = self.lift_sequences(compressor); if (compressor.option("comparisons")) switch (self.operator) { case "===": case "!==": if ((self.left.is_string(compressor) && self.right.is_string(compressor)) || (self.left.is_number(compressor) && self.right.is_number(compressor)) || (self.left.is_boolean() && self.right.is_boolean())) { self.operator = self.operator.substr(0, 2); } // XXX: intentionally falling down to the next case case "==": case "!=": // "undefined" == typeof x => undefined === x if (self.left instanceof AST_String && self.left.value == "undefined" && self.right instanceof AST_UnaryPrefix && self.right.operator == "typeof") { var expr = self.right.expression; if (expr instanceof AST_SymbolRef ? !expr.undeclared() : !(expr instanceof AST_PropAccess) || compressor.option("screw_ie8")) { self.right = expr; self.left = make_node(AST_Undefined, self.left).optimize(compressor); if (self.operator.length == 2) self.operator += "="; } } break; } if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) { var ll = self.left.evaluate(compressor); var rr = self.right.evaluate(compressor); if (ll && typeof ll == "string") { compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { car: self.right, cdr: make_node(AST_True, self) }).optimize(compressor); } if (rr && typeof rr == "string") { compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { car: self.left, cdr: make_node(AST_True, self) }).optimize(compressor); } } if (compressor.option("comparisons") && self.is_boolean()) { if (!(compressor.parent() instanceof AST_Binary) || compressor.parent() instanceof AST_Assign) { var negated = make_node(AST_UnaryPrefix, self, { operator: "!", expression: self.negate(compressor, first_in_statement(compressor)) }); self = best_of(compressor, self, negated); } if (compressor.option("unsafe_comps")) { switch (self.operator) { case "<": reverse(">"); break; case "<=": reverse(">="); break; } } } if (self.operator == "+") { if (self.right instanceof AST_String && self.right.getValue() == "" && self.left.is_string(compressor)) { return self.left; } if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) { return self.right; } if (self.left instanceof AST_Binary && self.left.operator == "+" && self.left.left instanceof AST_String && self.left.left.getValue() == "" && self.right.is_string(compressor)) { self.left = self.left.right; return self.transform(compressor); } } if (compressor.option("evaluate")) { switch (self.operator) { case "&&": var ll = self.left.evaluate(compressor); if (!ll) { compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.left).optimize(compressor); } else if (ll !== self.left) { compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.right).optimize(compressor); } if (compressor.option("booleans") && compressor.in_boolean_context()) { var rr = self.right.evaluate(compressor); if (!rr) { compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { car: self.left, cdr: make_node(AST_False, self) }).optimize(compressor); } else if (rr !== self.right) { compressor.warn("Dropping side-effect-free && in boolean context [{file}:{line},{col}]", self.start); return self.left.optimize(compressor); } } break; case "||": var ll = self.left.evaluate(compressor); if (!ll) { compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.right).optimize(compressor); } else if (ll !== self.left) { compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.left).optimize(compressor); } if (compressor.option("booleans") && compressor.in_boolean_context()) { var rr = self.right.evaluate(compressor); if (!rr) { compressor.warn("Dropping side-effect-free || in boolean context [{file}:{line},{col}]", self.start); return self.left.optimize(compressor); } else if (rr !== self.right) { compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); return make_node(AST_Seq, self, { car: self.left, cdr: make_node(AST_True, self) }).optimize(compressor); } } break; } var associative = true; switch (self.operator) { case "+": // "foo" + ("bar" + x) => "foobar" + x if (self.left instanceof AST_Constant && self.right instanceof AST_Binary && self.right.operator == "+" && self.right.left instanceof AST_Constant && self.right.is_string(compressor)) { self = make_node(AST_Binary, self, { operator: "+", left: make_node(AST_String, self.left, { value: "" + self.left.getValue() + self.right.left.getValue(), start: self.left.start, end: self.right.left.end }), right: self.right.right }); } // (x + "foo") + "bar" => x + "foobar" if (self.right instanceof AST_Constant && self.left instanceof AST_Binary && self.left.operator == "+" && self.left.right instanceof AST_Constant && self.left.is_string(compressor)) { self = make_node(AST_Binary, self, { operator: "+", left: self.left.left, right: make_node(AST_String, self.right, { value: "" + self.left.right.getValue() + self.right.getValue(), start: self.left.right.start, end: self.right.end }) }); } // (x + "foo") + ("bar" + y) => (x + "foobar") + y if (self.left instanceof AST_Binary && self.left.operator == "+" && self.left.is_string(compressor) && self.left.right instanceof AST_Constant && self.right instanceof AST_Binary && self.right.operator == "+" && self.right.left instanceof AST_Constant && self.right.is_string(compressor)) { self = make_node(AST_Binary, self, { operator: "+", left: make_node(AST_Binary, self.left, { operator: "+", left: self.left.left, right: make_node(AST_String, self.left.right, { value: "" + self.left.right.getValue() + self.right.left.getValue(), start: self.left.right.start, end: self.right.left.end }) }), right: self.right.right }); } // a + -b => a - b if (self.right instanceof AST_UnaryPrefix && self.right.operator == "-" && self.left.is_number(compressor)) { self = make_node(AST_Binary, self, { operator: "-", left: self.left, right: self.right.expression }); break; } // -a + b => b - a if (self.left instanceof AST_UnaryPrefix && self.left.operator == "-" && reversible() && self.right.is_number(compressor)) { self = make_node(AST_Binary, self, { operator: "-", left: self.right, right: self.left.expression }); break; } case "*": associative = compressor.option("unsafe_math"); case "&": case "|": case "^": // a + +b => +b + a if (self.left.is_number(compressor) && self.right.is_number(compressor) && reversible() && !(self.left instanceof AST_Binary && self.left.operator != self.operator && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { var reversed = make_node(AST_Binary, self, { operator: self.operator, left: self.right, right: self.left }); if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { self = best_of(compressor, reversed, self); } else { self = best_of(compressor, self, reversed); } } if (associative && self.is_number(compressor)) { // a + (b + c) => (a + b) + c if (self.right instanceof AST_Binary && self.right.operator == self.operator) { self = make_node(AST_Binary, self, { operator: self.operator, left: make_node(AST_Binary, self.left, { operator: self.operator, left: self.left, right: self.right.left, start: self.left.start, end: self.right.left.end }), right: self.right.right }); } // (n + 2) + 3 => 5 + n // (2 * n) * 3 => 6 + n if (self.right instanceof AST_Constant && self.left instanceof AST_Binary && self.left.operator == self.operator) { if (self.left.left instanceof AST_Constant) { self = make_node(AST_Binary, self, { operator: self.operator, left: make_node(AST_Binary, self.left, { operator: self.operator, left: self.left.left, right: self.right, start: self.left.left.start, end: self.right.end }), right: self.left.right }); } else if (self.left.right instanceof AST_Constant) { self = make_node(AST_Binary, self, { operator: self.operator, left: make_node(AST_Binary, self.left, { operator: self.operator, left: self.left.right, right: self.right, start: self.left.right.start, end: self.right.end }), right: self.left.left }); } } // (a | 1) | (2 | d) => (3 | a) | b if (self.left instanceof AST_Binary && self.left.operator == self.operator && self.left.right instanceof AST_Constant && self.right instanceof AST_Binary && self.right.operator == self.operator && self.right.left instanceof AST_Constant) { self = make_node(AST_Binary, self, { operator: self.operator, left: make_node(AST_Binary, self.left, { operator: self.operator, left: make_node(AST_Binary, self.left.left, { operator: self.operator, left: self.left.right, right: self.right.left, start: self.left.right.start, end: self.right.left.end }), right: self.left.left }), right: self.right.right }); } } } } // x && (y && z) ==> x && y && z // x || (y || z) ==> x || y || z // x + ("y" + z) ==> x + "y" + z // "x" + (y + "z")==> "x" + y + "z" if (self.right instanceof AST_Binary && self.right.operator == self.operator && (self.operator == "&&" || self.operator == "||" || (self.operator == "+" && (self.right.left.is_string(compressor) || (self.left.is_string(compressor) && self.right.right.is_string(compressor)))))) { self.left = make_node(AST_Binary, self.left, { operator : self.operator, left : self.left, right : self.right.left }); self.right = self.right.right; return self.transform(compressor); } var ev = self.evaluate(compressor); if (ev !== self) { ev = make_node_from_constant(ev, self).optimize(compressor); return best_of(compressor, ev, self); } return self; }); OPT(AST_SymbolRef, function(self, compressor){ var def = self.resolve_defines(compressor); if (def) { return def.optimize(compressor); } // testing against !self.scope.uses_with first is an optimization if (compressor.option("screw_ie8") && self.undeclared() && (!self.scope.uses_with || !compressor.find_parent(AST_With))) { switch (self.name) { case "undefined": return make_node(AST_Undefined, self).optimize(compressor); case "NaN": return make_node(AST_NaN, self).optimize(compressor); case "Infinity": return make_node(AST_Infinity, self).optimize(compressor); } } if (compressor.option("evaluate") && compressor.option("reduce_vars") && is_lhs(self, compressor.parent()) !== self) { var d = self.definition(); var fixed = self.fixed_value(); if (fixed) { if (d.should_replace === undefined) { var init = fixed.evaluate(compressor); if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) { init = make_node_from_constant(init, fixed); var value = init.optimize(compressor).print_to_string().length; var fn; if (has_symbol_ref(fixed)) { fn = function() { var result = init.optimize(compressor); return result === init ? result.clone(true) : result; }; } else { value = Math.min(value, fixed.print_to_string().length); fn = function() { var result = best_of_expression(init.optimize(compressor), fixed); return result === init || result === fixed ? result.clone(true) : result; }; } var name = d.name.length; var overhead = 0; if (compressor.option("unused") && (!d.global || compressor.option("toplevel"))) { overhead = (name + 2 + value) / d.references.length; } d.should_replace = value <= name + overhead ? fn : false; } else { d.should_replace = false; } } if (d.should_replace) { return d.should_replace(); } } } return self; function has_symbol_ref(value) { var found; value.walk(new TreeWalker(function(node) { if (node instanceof AST_SymbolRef) found = true; if (found) return true; })); return found; } }); function is_atomic(lhs, self) { return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE; } OPT(AST_Undefined, function(self, compressor){ if (compressor.option("unsafe")) { var undef = find_variable(compressor, "undefined"); if (undef) { var ref = make_node(AST_SymbolRef, self, { name : "undefined", scope : undef.scope, thedef : undef }); ref.is_undefined = true; return ref; } } var lhs = is_lhs(compressor.self(), compressor.parent()); if (lhs && is_atomic(lhs, self)) return self; return make_node(AST_UnaryPrefix, self, { operator: "void", expression: make_node(AST_Number, self, { value: 0 }) }); }); OPT(AST_Infinity, function(self, compressor){ var lhs = is_lhs(compressor.self(), compressor.parent()); if (lhs && is_atomic(lhs, self)) return self; if (compressor.option("keep_infinity") && !(lhs && !is_atomic(lhs, self)) && !find_variable(compressor, "Infinity")) return self; return make_node(AST_Binary, self, { operator: "/", left: make_node(AST_Number, self, { value: 1 }), right: make_node(AST_Number, self, { value: 0 }) }); }); OPT(AST_NaN, function(self, compressor){ var lhs = is_lhs(compressor.self(), compressor.parent()); if (lhs && !is_atomic(lhs, self) || find_variable(compressor, "NaN")) { return make_node(AST_Binary, self, { operator: "/", left: make_node(AST_Number, self, { value: 0 }), right: make_node(AST_Number, self, { value: 0 }) }); } return self; }); var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ]; OPT(AST_Assign, function(self, compressor){ self = self.lift_sequences(compressor); if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { // x = expr1 OP expr2 if (self.right.left instanceof AST_SymbolRef && self.right.left.name == self.left.name && member(self.right.operator, ASSIGN_OPS)) { // x = x - 2 ---> x -= 2 self.operator = self.right.operator + "="; self.right = self.right.right; } else if (self.right.right instanceof AST_SymbolRef && self.right.right.name == self.left.name && member(self.right.operator, ASSIGN_OPS_COMMUTATIVE) && !self.right.left.has_side_effects(compressor)) { // x = 2 & x ---> x &= 2 self.operator = self.right.operator + "="; self.right = self.right.left; } } return self; }); OPT(AST_Conditional, function(self, compressor){ if (!compressor.option("conditionals")) return self; if (self.condition instanceof AST_Seq) { var car = self.condition.car; self.condition = self.condition.cdr; return AST_Seq.cons(car, self); } var cond = self.condition.evaluate(compressor); if (cond !== self.condition) { if (cond) { compressor.warn("Condition always true [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.consequent); } else { compressor.warn("Condition always false [{file}:{line},{col}]", self.start); return maintain_this_binding(compressor.parent(), self, self.alternative); } } var negated = cond.negate(compressor, first_in_statement(compressor)); if (best_of(compressor, cond, negated) === negated) { self = make_node(AST_Conditional, self, { condition: negated, consequent: self.alternative, alternative: self.consequent }); } var condition = self.condition; var consequent = self.consequent; var alternative = self.alternative; // x?x:y --> x||y if (condition instanceof AST_SymbolRef && consequent instanceof AST_SymbolRef && condition.definition() === consequent.definition()) { return make_node(AST_Binary, self, { operator: "||", left: condition, right: alternative }); } // if (foo) exp = something; else exp = something_else; // | // v // exp = foo ? something : something_else; if (consequent instanceof AST_Assign && alternative instanceof AST_Assign && consequent.operator == alternative.operator && consequent.left.equivalent_to(alternative.left) && (!self.condition.has_side_effects(compressor) || consequent.operator == "=" && !consequent.left.has_side_effects(compressor))) { return make_node(AST_Assign, self, { operator: consequent.operator, left: consequent.left, right: make_node(AST_Conditional, self, { condition: self.condition, consequent: consequent.right, alternative: alternative.right }) }); } // x ? y(a) : y(b) --> y(x ? a : b) if (consequent instanceof AST_Call && alternative.TYPE === consequent.TYPE && consequent.args.length == 1 && alternative.args.length == 1 && consequent.expression.equivalent_to(alternative.expression) && !consequent.expression.has_side_effects(compressor)) { consequent.args[0] = make_node(AST_Conditional, self, { condition: self.condition, consequent: consequent.args[0], alternative: alternative.args[0] }); return consequent; } // x?y?z:a:a --> x&&y?z:a if (consequent instanceof AST_Conditional && consequent.alternative.equivalent_to(alternative)) { return make_node(AST_Conditional, self, { condition: make_node(AST_Binary, self, { left: self.condition, operator: "&&", right: consequent.condition }), consequent: consequent.consequent, alternative: alternative }); } // x ? y : y --> x, y if (consequent.equivalent_to(alternative)) { return make_node(AST_Seq, self, { car: self.condition, cdr: consequent }).optimize(compressor); } if (is_true(self.consequent)) { if (is_false(self.alternative)) { // c ? true : false ---> !!c return booleanize(self.condition); } // c ? true : x ---> !!c || x return make_node(AST_Binary, self, { operator: "||", left: booleanize(self.condition), right: self.alternative }); } if (is_false(self.consequent)) { if (is_true(self.alternative)) { // c ? false : true ---> !c return booleanize(self.condition.negate(compressor)); } // c ? false : x ---> !c && x return make_node(AST_Binary, self, { operator: "&&", left: booleanize(self.condition.negate(compressor)), right: self.alternative }); } if (is_true(self.alternative)) { // c ? x : true ---> !c || x return make_node(AST_Binary, self, { operator: "||", left: booleanize(self.condition.negate(compressor)), right: self.consequent }); } if (is_false(self.alternative)) { // c ? x : false ---> !!c && x return make_node(AST_Binary, self, { operator: "&&", left: booleanize(self.condition), right: self.consequent }); } return self; function booleanize(node) { if (node.is_boolean()) return node; // !!expression return make_node(AST_UnaryPrefix, node, { operator: "!", expression: node.negate(compressor) }); } // AST_True or !0 function is_true(node) { return node instanceof AST_True || (node instanceof AST_UnaryPrefix && node.operator == "!" && node.expression instanceof AST_Constant && !node.expression.value); } // AST_False or !1 function is_false(node) { return node instanceof AST_False || (node instanceof AST_UnaryPrefix && node.operator == "!" && node.expression instanceof AST_Constant && !!node.expression.value); } }); OPT(AST_Boolean, function(self, compressor){ if (compressor.option("booleans")) { var p = compressor.parent(); if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) { compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", { operator : p.operator, value : self.value, file : p.start.file, line : p.start.line, col : p.start.col, }); return make_node(AST_Number, self, { value: +self.value }); } return make_node(AST_UnaryPrefix, self, { operator: "!", expression: make_node(AST_Number, self, { value: 1 - self.value }) }); } return self; }); OPT(AST_Sub, function(self, compressor){ var prop = self.property; if (prop instanceof AST_String && compressor.option("properties")) { prop = prop.getValue(); if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) { return make_node(AST_Dot, self, { expression : self.expression, property : prop }).optimize(compressor); } var v = parseFloat(prop); if (!isNaN(v) && v.toString() == prop) { self.property = make_node(AST_Number, self.property, { value: v }); } } var ev = self.evaluate(compressor); if (ev !== self) { ev = make_node_from_constant(ev, self).optimize(compressor); return best_of(compressor, ev, self); } return self; }); OPT(AST_Dot, function(self, compressor){ var def = self.resolve_defines(compressor); if (def) { return def.optimize(compressor); } var prop = self.property; if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) { return make_node(AST_Sub, self, { expression : self.expression, property : make_node(AST_String, self, { value: prop }) }).optimize(compressor); } if (compressor.option("unsafe_proto") && self.expression instanceof AST_Dot && self.expression.property == "prototype") { var exp = self.expression.expression; if (exp instanceof AST_SymbolRef && exp.undeclared()) switch (exp.name) { case "Array": self.expression = make_node(AST_Array, self.expression, { elements: [] }); break; case "Object": self.expression = make_node(AST_Object, self.expression, { properties: [] }); break; case "String": self.expression = make_node(AST_String, self.expression, { value: "" }); break; } } var ev = self.evaluate(compressor); if (ev !== self) { ev = make_node_from_constant(ev, self).optimize(compressor); return best_of(compressor, ev, self); } return self; }); function literals_in_boolean_context(self, compressor) { if (compressor.option("booleans") && compressor.in_boolean_context()) { return best_of(compressor, self, make_node(AST_Seq, self, { car: self, cdr: make_node(AST_True, self) }).optimize(compressor)); } return self; }; OPT(AST_Array, literals_in_boolean_context); OPT(AST_Object, literals_in_boolean_context); OPT(AST_RegExp, literals_in_boolean_context); OPT(AST_Return, function(self, compressor){ if (self.value && is_undefined(self.value, compressor)) { self.value = null; } return self; }); OPT(AST_VarDef, function(self, compressor){ var defines = compressor.option("global_defs"); if (defines && HOP(defines, self.name.name)) { compressor.warn('global_defs ' + self.name.name + ' redefined [{file}:{line},{col}]', self.start); } return self; }); })(); UglifyJS2-2.8.29/lib/mozilla-ast.js000066400000000000000000000533711312030606600167400ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; (function(){ var normalize_directives = function(body) { var in_directive = true; for (var i = 0; i < body.length; i++) { if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) { body[i] = new AST_Directive({ start: body[i].start, end: body[i].end, value: body[i].body.value }); } else if (in_directive && !(body[i] instanceof AST_Statement && body[i].body instanceof AST_String)) { in_directive = false; } } return body; }; var MOZ_TO_ME = { Program: function(M) { return new AST_Toplevel({ start: my_start_token(M), end: my_end_token(M), body: normalize_directives(M.body.map(from_moz)) }); }, FunctionDeclaration: function(M) { return new AST_Defun({ start: my_start_token(M), end: my_end_token(M), name: from_moz(M.id), argnames: M.params.map(from_moz), body: normalize_directives(from_moz(M.body).body) }); }, FunctionExpression: function(M) { return new AST_Function({ start: my_start_token(M), end: my_end_token(M), name: from_moz(M.id), argnames: M.params.map(from_moz), body: normalize_directives(from_moz(M.body).body) }); }, ExpressionStatement: function(M) { return new AST_SimpleStatement({ start: my_start_token(M), end: my_end_token(M), body: from_moz(M.expression) }); }, TryStatement: function(M) { var handlers = M.handlers || [M.handler]; if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) { throw new Error("Multiple catch clauses are not supported."); } return new AST_Try({ start : my_start_token(M), end : my_end_token(M), body : from_moz(M.block).body, bcatch : from_moz(handlers[0]), bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null }); }, Property: function(M) { var key = M.key; var args = { start : my_start_token(key), end : my_end_token(M.value), key : key.type == "Identifier" ? key.name : key.value, value : from_moz(M.value) }; if (M.kind == "init") return new AST_ObjectKeyVal(args); args.key = new AST_SymbolAccessor({ name: args.key }); args.value = new AST_Accessor(args.value); if (M.kind == "get") return new AST_ObjectGetter(args); if (M.kind == "set") return new AST_ObjectSetter(args); }, ArrayExpression: function(M) { return new AST_Array({ start : my_start_token(M), end : my_end_token(M), elements : M.elements.map(function(elem){ return elem === null ? new AST_Hole() : from_moz(elem); }) }); }, ObjectExpression: function(M) { return new AST_Object({ start : my_start_token(M), end : my_end_token(M), properties : M.properties.map(function(prop){ prop.type = "Property"; return from_moz(prop) }) }); }, SequenceExpression: function(M) { return AST_Seq.from_array(M.expressions.map(from_moz)); }, MemberExpression: function(M) { return new (M.computed ? AST_Sub : AST_Dot)({ start : my_start_token(M), end : my_end_token(M), property : M.computed ? from_moz(M.property) : M.property.name, expression : from_moz(M.object) }); }, SwitchCase: function(M) { return new (M.test ? AST_Case : AST_Default)({ start : my_start_token(M), end : my_end_token(M), expression : from_moz(M.test), body : M.consequent.map(from_moz) }); }, VariableDeclaration: function(M) { return new (M.kind === "const" ? AST_Const : AST_Var)({ start : my_start_token(M), end : my_end_token(M), definitions : M.declarations.map(from_moz) }); }, Literal: function(M) { var val = M.value, args = { start : my_start_token(M), end : my_end_token(M) }; if (val === null) return new AST_Null(args); switch (typeof val) { case "string": args.value = val; return new AST_String(args); case "number": args.value = val; return new AST_Number(args); case "boolean": return new (val ? AST_True : AST_False)(args); default: var rx = M.regex; if (rx && rx.pattern) { // RegExpLiteral as per ESTree AST spec args.value = new RegExp(rx.pattern, rx.flags).toString(); } else { // support legacy RegExp args.value = M.regex && M.raw ? M.raw : val; } return new AST_RegExp(args); } }, Identifier: function(M) { var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; return new ( p.type == "LabeledStatement" ? AST_Label : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar) : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) : p.type == "CatchClause" ? AST_SymbolCatch : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef : AST_SymbolRef)({ start : my_start_token(M), end : my_end_token(M), name : M.name }); } }; MOZ_TO_ME.UpdateExpression = MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) { var prefix = "prefix" in M ? M.prefix : M.type == "UnaryExpression" ? true : false; return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ start : my_start_token(M), end : my_end_token(M), operator : M.operator, expression : from_moz(M.argument) }); }; map("EmptyStatement", AST_EmptyStatement); map("BlockStatement", AST_BlockStatement, "body@body"); map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative"); map("LabeledStatement", AST_LabeledStatement, "label>label, body>body"); map("BreakStatement", AST_Break, "label>label"); map("ContinueStatement", AST_Continue, "label>label"); map("WithStatement", AST_With, "object>expression, body>body"); map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body"); map("ReturnStatement", AST_Return, "argument>value"); map("ThrowStatement", AST_Throw, "argument>value"); map("WhileStatement", AST_While, "test>condition, body>body"); map("DoWhileStatement", AST_Do, "test>condition, body>body"); map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body"); map("ForInStatement", AST_ForIn, "left>init, right>object, body>body"); map("DebuggerStatement", AST_Debugger); map("VariableDeclarator", AST_VarDef, "id>name, init>value"); map("CatchClause", AST_Catch, "param>argname, body%body"); map("ThisExpression", AST_This); map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right"); map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); map("NewExpression", AST_New, "callee>expression, arguments@args"); map("CallExpression", AST_Call, "callee>expression, arguments@args"); def_to_moz(AST_Toplevel, function To_Moz_Program(M) { return to_moz_scope("Program", M); }); def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) { return { type: "FunctionDeclaration", id: to_moz(M.name), params: M.argnames.map(to_moz), body: to_moz_scope("BlockStatement", M) } }); def_to_moz(AST_Function, function To_Moz_FunctionExpression(M) { return { type: "FunctionExpression", id: to_moz(M.name), params: M.argnames.map(to_moz), body: to_moz_scope("BlockStatement", M) } }); def_to_moz(AST_Directive, function To_Moz_Directive(M) { return { type: "ExpressionStatement", expression: { type: "Literal", value: M.value } }; }); def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) { return { type: "ExpressionStatement", expression: to_moz(M.body) }; }); def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) { return { type: "SwitchCase", test: to_moz(M.expression), consequent: M.body.map(to_moz) }; }); def_to_moz(AST_Try, function To_Moz_TryStatement(M) { return { type: "TryStatement", block: to_moz_block(M), handler: to_moz(M.bcatch), guardedHandlers: [], finalizer: to_moz(M.bfinally) }; }); def_to_moz(AST_Catch, function To_Moz_CatchClause(M) { return { type: "CatchClause", param: to_moz(M.argname), guard: null, body: to_moz_block(M) }; }); def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) { return { type: "VariableDeclaration", kind: M instanceof AST_Const ? "const" : "var", declarations: M.definitions.map(to_moz) }; }); def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) { return { type: "SequenceExpression", expressions: M.to_array().map(to_moz) }; }); def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) { var isComputed = M instanceof AST_Sub; return { type: "MemberExpression", object: to_moz(M.expression), computed: isComputed, property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property} }; }); def_to_moz(AST_Unary, function To_Moz_Unary(M) { return { type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression", operator: M.operator, prefix: M instanceof AST_UnaryPrefix, argument: to_moz(M.expression) }; }); def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) { return { type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression", left: to_moz(M.left), operator: M.operator, right: to_moz(M.right) }; }); def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) { return { type: "ArrayExpression", elements: M.elements.map(to_moz) }; }); def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) { return { type: "ObjectExpression", properties: M.properties.map(to_moz) }; }); def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) { var key = { type: "Literal", value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key }; var kind; if (M instanceof AST_ObjectKeyVal) { kind = "init"; } else if (M instanceof AST_ObjectGetter) { kind = "get"; } else if (M instanceof AST_ObjectSetter) { kind = "set"; } return { type: "Property", kind: kind, key: key, value: to_moz(M.value) }; }); def_to_moz(AST_Symbol, function To_Moz_Identifier(M) { var def = M.definition(); return { type: "Identifier", name: def ? def.mangled_name || def.name : M.name }; }); def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) { var value = M.value; return { type: "Literal", value: value, raw: value.toString(), regex: { pattern: value.source, flags: value.toString().match(/[gimuy]*$/)[0] } }; }); def_to_moz(AST_Constant, function To_Moz_Literal(M) { var value = M.value; if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) { return { type: "UnaryExpression", operator: "-", prefix: true, argument: { type: "Literal", value: -value, raw: M.start.raw } }; } return { type: "Literal", value: value, raw: M.start.raw }; }); def_to_moz(AST_Atom, function To_Moz_Atom(M) { return { type: "Identifier", name: String(M.value) }; }); AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null }); AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast); AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast); /* -----[ tools ]----- */ function raw_token(moznode) { if (moznode.type == "Literal") { return moznode.raw != null ? moznode.raw : moznode.value + ""; } } function my_start_token(moznode) { var loc = moznode.loc, start = loc && loc.start; var range = moznode.range; return new AST_Token({ file : loc && loc.source, line : start && start.line, col : start && start.column, pos : range ? range[0] : moznode.start, endline : start && start.line, endcol : start && start.column, endpos : range ? range[0] : moznode.start, raw : raw_token(moznode), }); }; function my_end_token(moznode) { var loc = moznode.loc, end = loc && loc.end; var range = moznode.range; return new AST_Token({ file : loc && loc.source, line : end && end.line, col : end && end.column, pos : range ? range[1] : moznode.end, endline : end && end.line, endcol : end && end.column, endpos : range ? range[1] : moznode.end, raw : raw_token(moznode), }); }; function map(moztype, mytype, propmap) { var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; moz_to_me += "return new U2." + mytype.name + "({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)"; var me_to_moz = "function To_Moz_" + moztype + "(M){\n"; me_to_moz += "return {\n" + "type: " + JSON.stringify(moztype); if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){ var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); if (!m) throw new Error("Can't understand property map: " + prop); var moz = m[1], how = m[2], my = m[3]; moz_to_me += ",\n" + my + ": "; me_to_moz += ",\n" + moz + ": "; switch (how) { case "@": moz_to_me += "M." + moz + ".map(from_moz)"; me_to_moz += "M." + my + ".map(to_moz)"; break; case ">": moz_to_me += "from_moz(M." + moz + ")"; me_to_moz += "to_moz(M." + my + ")"; break; case "=": moz_to_me += "M." + moz; me_to_moz += "M." + my; break; case "%": moz_to_me += "from_moz(M." + moz + ").body"; me_to_moz += "to_moz_block(M)"; break; default: throw new Error("Can't understand operator in propmap: " + prop); } }); moz_to_me += "\n})\n}"; me_to_moz += "\n}\n}"; //moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true }); //console.log(moz_to_me); moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( exports, my_start_token, my_end_token, from_moz ); me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")( to_moz, to_moz_block, to_moz_scope ); MOZ_TO_ME[moztype] = moz_to_me; def_to_moz(mytype, me_to_moz); }; var FROM_MOZ_STACK = null; function from_moz(node) { FROM_MOZ_STACK.push(node); var ret = node != null ? MOZ_TO_ME[node.type](node) : null; FROM_MOZ_STACK.pop(); return ret; }; AST_Node.from_mozilla_ast = function(node){ var save_stack = FROM_MOZ_STACK; FROM_MOZ_STACK = []; var ast = from_moz(node); FROM_MOZ_STACK = save_stack; return ast; }; function set_moz_loc(mynode, moznode, myparent) { var start = mynode.start; var end = mynode.end; if (start.pos != null && end.endpos != null) { moznode.range = [start.pos, end.endpos]; } if (start.line) { moznode.loc = { start: {line: start.line, column: start.col}, end: end.endline ? {line: end.endline, column: end.endcol} : null }; if (start.file) { moznode.loc.source = start.file; } } return moznode; }; function def_to_moz(mytype, handler) { mytype.DEFMETHOD("to_mozilla_ast", function() { return set_moz_loc(this, handler(this)); }); }; function to_moz(node) { return node != null ? node.to_mozilla_ast() : null; }; function to_moz_block(node) { return { type: "BlockStatement", body: node.body.map(to_moz) }; }; function to_moz_scope(type, node) { var body = node.body.map(to_moz); if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) { body.unshift(to_moz(new AST_EmptyStatement(node.body[0]))); } return { type: type, body: body }; }; })(); UglifyJS2-2.8.29/lib/output.js000066400000000000000000001355771312030606600160550ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/; function is_some_comments(comment) { // multiline comment return comment.type == "comment2" && /@preserve|@license|@cc_on/i.test(comment.value); } function OutputStream(options) { options = defaults(options, { ascii_only : false, beautify : false, bracketize : false, comments : false, indent_level : 4, indent_start : 0, inline_script : true, keep_quoted_props: false, max_line_len : false, preamble : null, preserve_line : false, quote_keys : false, quote_style : 0, screw_ie8 : true, semicolons : true, shebang : true, source_map : null, space_colon : true, unescape_regexps : false, width : 80, wrap_iife : false, }, true); // Convert comment option to RegExp if neccessary and set up comments filter var comment_filter = return_false; // Default case, throw all comments away if (options.comments) { var comments = options.comments; if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) { var regex_pos = options.comments.lastIndexOf("/"); comments = new RegExp( options.comments.substr(1, regex_pos - 1), options.comments.substr(regex_pos + 1) ); } if (comments instanceof RegExp) { comment_filter = function(comment) { return comment.type != "comment5" && comments.test(comment.value); }; } else if (typeof comments === "function") { comment_filter = function(comment) { return comment.type != "comment5" && comments(this, comment); }; } else if (comments === "some") { comment_filter = is_some_comments; } else { // NOTE includes "all" option comment_filter = return_true; } } var indentation = 0; var current_col = 0; var current_line = 1; var current_pos = 0; var OUTPUT = ""; function to_ascii(str, identifier) { return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { var code = ch.charCodeAt(0).toString(16); if (code.length <= 2 && !identifier) { while (code.length < 2) code = "0" + code; return "\\x" + code; } else { while (code.length < 4) code = "0" + code; return "\\u" + code; } }); }; function make_string(str, quote) { var dq = 0, sq = 0; str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s, i){ switch (s) { case '"': ++dq; return '"'; case "'": ++sq; return "'"; case "\\": return "\\\\"; case "\n": return "\\n"; case "\r": return "\\r"; case "\t": return "\\t"; case "\b": return "\\b"; case "\f": return "\\f"; case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B"; case "\u2028": return "\\u2028"; case "\u2029": return "\\u2029"; case "\ufeff": return "\\ufeff"; case "\0": return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0"; } return s; }); function quote_single() { return "'" + str.replace(/\x27/g, "\\'") + "'"; } function quote_double() { return '"' + str.replace(/\x22/g, '\\"') + '"'; } if (options.ascii_only) str = to_ascii(str); switch (options.quote_style) { case 1: return quote_single(); case 2: return quote_double(); case 3: return quote == "'" ? quote_single() : quote_double(); default: return dq > sq ? quote_single() : quote_double(); } }; function encode_string(str, quote) { var ret = make_string(str, quote); if (options.inline_script) { ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); ret = ret.replace(/\x3c!--/g, "\\x3c!--"); ret = ret.replace(/--\x3e/g, "--\\x3e"); } return ret; }; function make_name(name) { name = name.toString(); if (options.ascii_only) name = to_ascii(name, true); return name; }; function make_indent(back) { return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); }; /* -----[ beautification/minification ]----- */ var might_need_space = false; var might_need_semicolon = false; var might_add_newline = 0; var last = ""; var ensure_line_len = options.max_line_len ? function() { if (current_col > options.max_line_len) { if (might_add_newline) { var left = OUTPUT.slice(0, might_add_newline); var right = OUTPUT.slice(might_add_newline); OUTPUT = left + "\n" + right; current_line++; current_pos++; current_col = right.length; } if (current_col > options.max_line_len) { AST_Node.warn("Output exceeds {max_line_len} characters", options); } } might_add_newline = 0; } : noop; var requireSemicolonChars = makePredicate("( [ + * / - , ."); function print(str) { str = String(str); var ch = str.charAt(0); var prev = last.charAt(last.length - 1); if (might_need_semicolon) { might_need_semicolon = false; if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") { if (options.semicolons || requireSemicolonChars(ch)) { OUTPUT += ";"; current_col++; current_pos++; } else { ensure_line_len(); OUTPUT += "\n"; current_pos++; current_line++; current_col = 0; if (/^\s+$/.test(str)) { // reset the semicolon flag, since we didn't print one // now and might still have to later might_need_semicolon = true; } } if (!options.beautify) might_need_space = false; } } if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { var target_line = stack[stack.length - 1].start.line; while (current_line < target_line) { ensure_line_len(); OUTPUT += "\n"; current_pos++; current_line++; current_col = 0; might_need_space = false; } } if (might_need_space) { if ((is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\")) || (ch == "/" && ch == prev) || ((ch == "+" || ch == "-") && ch == last)) { OUTPUT += " "; current_col++; current_pos++; } might_need_space = false; } OUTPUT += str; current_pos += str.length; var a = str.split(/\r?\n/), n = a.length - 1; current_line += n; current_col += a[0].length; if (n > 0) { ensure_line_len(); current_col = a[n].length; } last = str; }; var space = options.beautify ? function() { print(" "); } : function() { might_need_space = true; }; var indent = options.beautify ? function(half) { if (options.beautify) { print(make_indent(half ? 0.5 : 0)); } } : noop; var with_indent = options.beautify ? function(col, cont) { if (col === true) col = next_indent(); var save_indentation = indentation; indentation = col; var ret = cont(); indentation = save_indentation; return ret; } : function(col, cont) { return cont() }; var newline = options.beautify ? function() { print("\n"); } : options.max_line_len ? function() { ensure_line_len(); might_add_newline = OUTPUT.length; } : noop; var semicolon = options.beautify ? function() { print(";"); } : function() { might_need_semicolon = true; }; function force_semicolon() { might_need_semicolon = false; print(";"); }; function next_indent() { return indentation + options.indent_level; }; function with_block(cont) { var ret; print("{"); newline(); with_indent(next_indent(), function(){ ret = cont(); }); indent(); print("}"); return ret; }; function with_parens(cont) { print("("); //XXX: still nice to have that for argument lists //var ret = with_indent(current_col, cont); var ret = cont(); print(")"); return ret; }; function with_square(cont) { print("["); //var ret = with_indent(current_col, cont); var ret = cont(); print("]"); return ret; }; function comma() { print(","); space(); }; function colon() { print(":"); if (options.space_colon) space(); }; var add_mapping = options.source_map ? function(token, name) { try { if (token) options.source_map.add( token.file || "?", current_line, current_col, token.line, token.col, (!name && token.type == "name") ? token.value : name ); } catch(ex) { AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { file: token.file, line: token.line, col: token.col, cline: current_line, ccol: current_col, name: name || "" }) } } : noop; function get() { if (might_add_newline) { ensure_line_len(); } return OUTPUT; }; var stack = []; return { get : get, toString : get, indent : indent, indentation : function() { return indentation }, current_width : function() { return current_col - indentation }, should_break : function() { return options.width && this.current_width() >= options.width }, newline : newline, print : print, space : space, comma : comma, colon : colon, last : function() { return last }, semicolon : semicolon, force_semicolon : force_semicolon, to_ascii : to_ascii, print_name : function(name) { print(make_name(name)) }, print_string : function(str, quote, escape_directive) { var encoded = encode_string(str, quote); if (escape_directive === true && encoded.indexOf("\\") === -1) { // Insert semicolons to break directive prologue if (!EXPECT_DIRECTIVE.test(OUTPUT)) { force_semicolon(); } force_semicolon(); } print(encoded); }, encode_string : encode_string, next_indent : next_indent, with_indent : with_indent, with_block : with_block, with_parens : with_parens, with_square : with_square, add_mapping : add_mapping, option : function(opt) { return options[opt] }, comment_filter : comment_filter, line : function() { return current_line }, col : function() { return current_col }, pos : function() { return current_pos }, push_node : function(node) { stack.push(node) }, pop_node : function() { return stack.pop() }, parent : function(n) { return stack[stack.length - 2 - (n || 0)]; } }; }; /* -----[ code generators ]----- */ (function(){ /* -----[ utils ]----- */ function DEFPRINT(nodetype, generator) { nodetype.DEFMETHOD("_codegen", generator); }; var use_asm = false; var in_directive = false; AST_Node.DEFMETHOD("print", function(stream, force_parens){ var self = this, generator = self._codegen, prev_use_asm = use_asm; if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) { use_asm = true; } function doit() { self.add_comments(stream); self.add_source_map(stream); generator(self, stream); } stream.push_node(self); if (force_parens || self.needs_parens(stream)) { stream.with_parens(doit); } else { doit(); } stream.pop_node(); if (self instanceof AST_Scope) { use_asm = prev_use_asm; } }); AST_Node.DEFMETHOD("print_to_string", function(options){ var s = OutputStream(options); if (!options) s._readonly = true; this.print(s); return s.get(); }); /* -----[ comments ]----- */ AST_Node.DEFMETHOD("add_comments", function(output){ if (output._readonly) return; var self = this; var start = self.start; if (start && !start._comments_dumped) { start._comments_dumped = true; var comments = start.comments_before || []; // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 // and https://github.com/mishoo/UglifyJS2/issues/372 if (self instanceof AST_Exit && self.value) { self.value.walk(new TreeWalker(function(node){ if (node.start && node.start.comments_before) { comments = comments.concat(node.start.comments_before); node.start.comments_before = []; } if (node instanceof AST_Function || node instanceof AST_Array || node instanceof AST_Object) { return true; // don't go inside. } })); } if (output.pos() == 0) { if (comments.length > 0 && output.option("shebang") && comments[0].type == "comment5") { output.print("#!" + comments.shift().value + "\n"); output.indent(); } var preamble = output.option("preamble"); if (preamble) { output.print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); } } comments = comments.filter(output.comment_filter, self); // Keep single line comments after nlb, after nlb if (!output.option("beautify") && comments.length > 0 && /comment[134]/.test(comments[0].type) && output.col() !== 0 && comments[0].nlb) { output.print("\n"); } comments.forEach(function(c){ if (/comment[134]/.test(c.type)) { output.print("//" + c.value + "\n"); output.indent(); } else if (c.type == "comment2") { output.print("/*" + c.value + "*/"); if (start.nlb) { output.print("\n"); output.indent(); } else { output.space(); } } }); } }); /* -----[ PARENTHESES ]----- */ function PARENS(nodetype, func) { if (Array.isArray(nodetype)) { nodetype.forEach(function(nodetype){ PARENS(nodetype, func); }); } else { nodetype.DEFMETHOD("needs_parens", func); } }; PARENS(AST_Node, function(){ return false; }); // a function expression needs parens around it when it's provably // the first token to appear in a statement. PARENS(AST_Function, function(output){ if (first_in_statement(output)) { return true; } if (output.option('wrap_iife')) { var p = output.parent(); return p instanceof AST_Call && p.expression === this; } return false; }); // same goes for an object literal, because otherwise it would be // interpreted as a block of code. PARENS(AST_Object, function(output){ return first_in_statement(output); }); PARENS(AST_Unary, function(output){ var p = output.parent(); return p instanceof AST_PropAccess && p.expression === this || p instanceof AST_Call && p.expression === this; }); PARENS(AST_Seq, function(output){ var p = output.parent(); return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) || p instanceof AST_Unary // !(foo, bar, baz) || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2 || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) * ==> 20 (side effect, set a := 10 and b := 20) */ ; }); PARENS(AST_Binary, function(output){ var p = output.parent(); // (foo && bar)() if (p instanceof AST_Call && p.expression === this) return true; // typeof (foo && bar) if (p instanceof AST_Unary) return true; // (foo && bar)["prop"], (foo && bar).prop if (p instanceof AST_PropAccess && p.expression === this) return true; // this deals with precedence: 3 * (2 + 1) if (p instanceof AST_Binary) { var po = p.operator, pp = PRECEDENCE[po]; var so = this.operator, sp = PRECEDENCE[so]; if (pp > sp || (pp == sp && this === p.right)) { return true; } } }); PARENS(AST_PropAccess, function(output){ var p = output.parent(); if (p instanceof AST_New && p.expression === this) { // i.e. new (foo.bar().baz) // // if there's one call into this subtree, then we need // parens around it too, otherwise the call will be // interpreted as passing the arguments to the upper New // expression. try { this.walk(new TreeWalker(function(node){ if (node instanceof AST_Call) throw p; })); } catch(ex) { if (ex !== p) throw ex; return true; } } }); PARENS(AST_Call, function(output){ var p = output.parent(), p1; if (p instanceof AST_New && p.expression === this) return true; // workaround for Safari bug. // https://bugs.webkit.org/show_bug.cgi?id=123506 return this.expression instanceof AST_Function && p instanceof AST_PropAccess && p.expression === this && (p1 = output.parent(1)) instanceof AST_Assign && p1.left === p; }); PARENS(AST_New, function(output){ var p = output.parent(); if (!need_constructor_parens(this, output) && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]() || p instanceof AST_Call && p.expression === this)) // (new foo)(bar) return true; }); PARENS(AST_Number, function(output){ var p = output.parent(); if (p instanceof AST_PropAccess && p.expression === this) { var value = this.getValue(); if (value < 0 || /^0/.test(make_num(value))) { return true; } } }); PARENS([ AST_Assign, AST_Conditional ], function (output){ var p = output.parent(); // !(a = false) → true if (p instanceof AST_Unary) return true; // 1 + (a = 2) + 3 → 6, side effect setting a = 2 if (p instanceof AST_Binary && !(p instanceof AST_Assign)) return true; // (a = func)() —or— new (a = Object)() if (p instanceof AST_Call && p.expression === this) return true; // (a = foo) ? bar : baz if (p instanceof AST_Conditional && p.condition === this) return true; // (a = foo)["prop"] —or— (a = foo).prop if (p instanceof AST_PropAccess && p.expression === this) return true; }); /* -----[ PRINTERS ]----- */ DEFPRINT(AST_Directive, function(self, output){ output.print_string(self.value, self.quote); output.semicolon(); }); DEFPRINT(AST_Debugger, function(self, output){ output.print("debugger"); output.semicolon(); }); /* -----[ statements ]----- */ function display_body(body, is_toplevel, output, allow_directives) { var last = body.length - 1; in_directive = allow_directives; body.forEach(function(stmt, i){ if (in_directive === true && !(stmt instanceof AST_Directive || stmt instanceof AST_EmptyStatement || (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String) )) { in_directive = false; } if (!(stmt instanceof AST_EmptyStatement)) { output.indent(); stmt.print(output); if (!(i == last && is_toplevel)) { output.newline(); if (is_toplevel) output.newline(); } } if (in_directive === true && stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String ) { in_directive = false; } }); in_directive = false; }; AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){ force_statement(this.body, output); }); DEFPRINT(AST_Statement, function(self, output){ self.body.print(output); output.semicolon(); }); DEFPRINT(AST_Toplevel, function(self, output){ display_body(self.body, true, output, true); output.print(""); }); DEFPRINT(AST_LabeledStatement, function(self, output){ self.label.print(output); output.colon(); self.body.print(output); }); DEFPRINT(AST_SimpleStatement, function(self, output){ self.body.print(output); output.semicolon(); }); function print_bracketed(body, output, allow_directives) { if (body.length > 0) output.with_block(function(){ display_body(body, false, output, allow_directives); }); else output.print("{}"); }; DEFPRINT(AST_BlockStatement, function(self, output){ print_bracketed(self.body, output); }); DEFPRINT(AST_EmptyStatement, function(self, output){ output.semicolon(); }); DEFPRINT(AST_Do, function(self, output){ output.print("do"); output.space(); make_block(self.body, output); output.space(); output.print("while"); output.space(); output.with_parens(function(){ self.condition.print(output); }); output.semicolon(); }); DEFPRINT(AST_While, function(self, output){ output.print("while"); output.space(); output.with_parens(function(){ self.condition.print(output); }); output.space(); self._do_print_body(output); }); DEFPRINT(AST_For, function(self, output){ output.print("for"); output.space(); output.with_parens(function(){ if (self.init) { if (self.init instanceof AST_Definitions) { self.init.print(output); } else { parenthesize_for_noin(self.init, output, true); } output.print(";"); output.space(); } else { output.print(";"); } if (self.condition) { self.condition.print(output); output.print(";"); output.space(); } else { output.print(";"); } if (self.step) { self.step.print(output); } }); output.space(); self._do_print_body(output); }); DEFPRINT(AST_ForIn, function(self, output){ output.print("for"); output.space(); output.with_parens(function(){ self.init.print(output); output.space(); output.print("in"); output.space(); self.object.print(output); }); output.space(); self._do_print_body(output); }); DEFPRINT(AST_With, function(self, output){ output.print("with"); output.space(); output.with_parens(function(){ self.expression.print(output); }); output.space(); self._do_print_body(output); }); /* -----[ functions ]----- */ AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){ var self = this; if (!nokeyword) { output.print("function"); } if (self.name) { output.space(); self.name.print(output); } output.with_parens(function(){ self.argnames.forEach(function(arg, i){ if (i) output.comma(); arg.print(output); }); }); output.space(); print_bracketed(self.body, output, true); }); DEFPRINT(AST_Lambda, function(self, output){ self._do_print(output); }); /* -----[ exits ]----- */ AST_Exit.DEFMETHOD("_do_print", function(output, kind){ output.print(kind); if (this.value) { output.space(); this.value.print(output); } output.semicolon(); }); DEFPRINT(AST_Return, function(self, output){ self._do_print(output, "return"); }); DEFPRINT(AST_Throw, function(self, output){ self._do_print(output, "throw"); }); /* -----[ loop control ]----- */ AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){ output.print(kind); if (this.label) { output.space(); this.label.print(output); } output.semicolon(); }); DEFPRINT(AST_Break, function(self, output){ self._do_print(output, "break"); }); DEFPRINT(AST_Continue, function(self, output){ self._do_print(output, "continue"); }); /* -----[ if ]----- */ function make_then(self, output) { var b = self.body; if (output.option("bracketize") || !output.option("screw_ie8") && b instanceof AST_Do) return make_block(b, output); // The squeezer replaces "block"-s that contain only a single // statement with the statement itself; technically, the AST // is correct, but this can create problems when we output an // IF having an ELSE clause where the THEN clause ends in an // IF *without* an ELSE block (then the outer ELSE would refer // to the inner IF). This function checks for this case and // adds the block brackets if needed. if (!b) return output.force_semicolon(); while (true) { if (b instanceof AST_If) { if (!b.alternative) { make_block(self.body, output); return; } b = b.alternative; } else if (b instanceof AST_StatementWithBody) { b = b.body; } else break; } force_statement(self.body, output); }; DEFPRINT(AST_If, function(self, output){ output.print("if"); output.space(); output.with_parens(function(){ self.condition.print(output); }); output.space(); if (self.alternative) { make_then(self, output); output.space(); output.print("else"); output.space(); if (self.alternative instanceof AST_If) self.alternative.print(output); else force_statement(self.alternative, output); } else { self._do_print_body(output); } }); /* -----[ switch ]----- */ DEFPRINT(AST_Switch, function(self, output){ output.print("switch"); output.space(); output.with_parens(function(){ self.expression.print(output); }); output.space(); var last = self.body.length - 1; if (last < 0) output.print("{}"); else output.with_block(function(){ self.body.forEach(function(branch, i){ output.indent(true); branch.print(output); if (i < last && branch.body.length > 0) output.newline(); }); }); }); AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){ output.newline(); this.body.forEach(function(stmt){ output.indent(); stmt.print(output); output.newline(); }); }); DEFPRINT(AST_Default, function(self, output){ output.print("default:"); self._do_print_body(output); }); DEFPRINT(AST_Case, function(self, output){ output.print("case"); output.space(); self.expression.print(output); output.print(":"); self._do_print_body(output); }); /* -----[ exceptions ]----- */ DEFPRINT(AST_Try, function(self, output){ output.print("try"); output.space(); print_bracketed(self.body, output); if (self.bcatch) { output.space(); self.bcatch.print(output); } if (self.bfinally) { output.space(); self.bfinally.print(output); } }); DEFPRINT(AST_Catch, function(self, output){ output.print("catch"); output.space(); output.with_parens(function(){ self.argname.print(output); }); output.space(); print_bracketed(self.body, output); }); DEFPRINT(AST_Finally, function(self, output){ output.print("finally"); output.space(); print_bracketed(self.body, output); }); /* -----[ var/const ]----- */ AST_Definitions.DEFMETHOD("_do_print", function(output, kind){ output.print(kind); output.space(); this.definitions.forEach(function(def, i){ if (i) output.comma(); def.print(output); }); var p = output.parent(); var in_for = p instanceof AST_For || p instanceof AST_ForIn; var avoid_semicolon = in_for && p.init === this; if (!avoid_semicolon) output.semicolon(); }); DEFPRINT(AST_Var, function(self, output){ self._do_print(output, "var"); }); DEFPRINT(AST_Const, function(self, output){ self._do_print(output, "const"); }); function parenthesize_for_noin(node, output, noin) { if (!noin) node.print(output); else try { // need to take some precautions here: // https://github.com/mishoo/UglifyJS2/issues/60 node.walk(new TreeWalker(function(node){ if (node instanceof AST_Binary && node.operator == "in") throw output; })); node.print(output); } catch(ex) { if (ex !== output) throw ex; node.print(output, true); } }; DEFPRINT(AST_VarDef, function(self, output){ self.name.print(output); if (self.value) { output.space(); output.print("="); output.space(); var p = output.parent(1); var noin = p instanceof AST_For || p instanceof AST_ForIn; parenthesize_for_noin(self.value, output, noin); } }); /* -----[ other expressions ]----- */ DEFPRINT(AST_Call, function(self, output){ self.expression.print(output); if (self instanceof AST_New && !need_constructor_parens(self, output)) return; output.with_parens(function(){ self.args.forEach(function(expr, i){ if (i) output.comma(); expr.print(output); }); }); }); DEFPRINT(AST_New, function(self, output){ output.print("new"); output.space(); AST_Call.prototype._codegen(self, output); }); AST_Seq.DEFMETHOD("_do_print", function(output){ this.car.print(output); if (this.cdr) { output.comma(); if (output.should_break()) { output.newline(); output.indent(); } this.cdr.print(output); } }); DEFPRINT(AST_Seq, function(self, output){ self._do_print(output); // var p = output.parent(); // if (p instanceof AST_Statement) { // output.with_indent(output.next_indent(), function(){ // self._do_print(output); // }); // } else { // self._do_print(output); // } }); DEFPRINT(AST_Dot, function(self, output){ var expr = self.expression; expr.print(output); if (expr instanceof AST_Number && expr.getValue() >= 0) { if (!/[xa-f.)]/i.test(output.last())) { output.print("."); } } output.print("."); // the name after dot would be mapped about here. output.add_mapping(self.end); output.print_name(self.property); }); DEFPRINT(AST_Sub, function(self, output){ self.expression.print(output); output.print("["); self.property.print(output); output.print("]"); }); DEFPRINT(AST_UnaryPrefix, function(self, output){ var op = self.operator; output.print(op); if (/^[a-z]/i.test(op) || (/[+-]$/.test(op) && self.expression instanceof AST_UnaryPrefix && /^[+-]/.test(self.expression.operator))) { output.space(); } self.expression.print(output); }); DEFPRINT(AST_UnaryPostfix, function(self, output){ self.expression.print(output); output.print(self.operator); }); DEFPRINT(AST_Binary, function(self, output){ var op = self.operator; self.left.print(output); if (op[0] == ">" /* ">>" ">>>" ">" ">=" */ && self.left instanceof AST_UnaryPostfix && self.left.operator == "--") { // space is mandatory to avoid outputting --> output.print(" "); } else { // the space is optional depending on "beautify" output.space(); } output.print(op); if ((op == "<" || op == "<<") && self.right instanceof AST_UnaryPrefix && self.right.operator == "!" && self.right.expression instanceof AST_UnaryPrefix && self.right.expression.operator == "--") { // space is mandatory to avoid outputting ") && S.newline_before) { forward(3); skip_line_comment("comment4"); continue; } } var ch = peek(); if (!ch) return token("eof"); var code = ch.charCodeAt(0); switch (code) { case 34: case 39: return read_string(ch); case 46: return handle_dot(); case 47: { var tok = handle_slash(); if (tok === next_token) continue; return tok; } } if (is_digit(code)) return read_num(); if (PUNC_CHARS(ch)) return token("punc", next()); if (OPERATOR_CHARS(ch)) return read_operator(); if (code == 92 || is_identifier_start(code)) return read_word(); break; } parse_error("Unexpected character '" + ch + "'"); }; next_token.context = function(nc) { if (nc) S = nc; return S; }; next_token.add_directive = function(directive) { S.directive_stack[S.directive_stack.length - 1].push(directive); if (S.directives[directive] === undefined) { S.directives[directive] = 1; } else { S.directives[directive]++; } } next_token.push_directives_stack = function() { S.directive_stack.push([]); } next_token.pop_directives_stack = function() { var directives = S.directive_stack[S.directive_stack.length - 1]; for (var i = 0; i < directives.length; i++) { S.directives[directives[i]]--; } S.directive_stack.pop(); } next_token.has_directive = function(directive) { return S.directives[directive] !== undefined && S.directives[directive] > 0; } return next_token; }; /* -----[ Parser (constants) ]----- */ var UNARY_PREFIX = makePredicate([ "typeof", "void", "delete", "--", "++", "!", "~", "-", "+" ]); var UNARY_POSTFIX = makePredicate([ "--", "++" ]); var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); var PRECEDENCE = (function(a, ret){ for (var i = 0; i < a.length; ++i) { var b = a[i]; for (var j = 0; j < b.length; ++j) { ret[b[j]] = i + 1; } } return ret; })( [ ["||"], ["&&"], ["|"], ["^"], ["&"], ["==", "===", "!=", "!=="], ["<", ">", "<=", ">=", "in", "instanceof"], [">>", "<<", ">>>"], ["+", "-"], ["*", "/", "%"] ], {} ); var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); /* -----[ Parser ]----- */ function parse($TEXT, options) { options = defaults(options, { bare_returns : false, cli : false, expression : false, filename : null, html5_comments : true, shebang : true, strict : false, toplevel : null, }); var S = { input : (typeof $TEXT == "string" ? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang) : $TEXT), token : null, prev : null, peeked : null, in_function : 0, in_directives : true, in_loop : 0, labels : [] }; S.token = next(); function is(type, value) { return is_token(S.token, type, value); }; function peek() { return S.peeked || (S.peeked = S.input()); }; function next() { S.prev = S.token; if (S.peeked) { S.token = S.peeked; S.peeked = null; } else { S.token = S.input(); } S.in_directives = S.in_directives && ( S.token.type == "string" || is("punc", ";") ); return S.token; }; function prev() { return S.prev; }; function croak(msg, line, col, pos) { var ctx = S.input.context(); js_error(msg, ctx.filename, line != null ? line : ctx.tokline, col != null ? col : ctx.tokcol, pos != null ? pos : ctx.tokpos); }; function token_error(token, msg) { croak(msg, token.line, token.col); }; function unexpected(token) { if (token == null) token = S.token; token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); }; function expect_token(type, val) { if (is(type, val)) { return next(); } token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); }; function expect(punc) { return expect_token("punc", punc); }; function can_insert_semicolon() { return !options.strict && ( S.token.nlb || is("eof") || is("punc", "}") ); }; function semicolon(optional) { if (is("punc", ";")) next(); else if (!optional && !can_insert_semicolon()) unexpected(); }; function parenthesised() { expect("("); var exp = expression(true); expect(")"); return exp; }; function embed_tokens(parser) { return function() { var start = S.token; var expr = parser(); var end = prev(); expr.start = start; expr.end = end; return expr; }; }; function handle_regexp() { if (is("operator", "/") || is("operator", "/=")) { S.peeked = null; S.token = S.input(S.token.value.substr(1)); // force regexp } }; var statement = embed_tokens(function() { handle_regexp(); switch (S.token.type) { case "string": if (S.in_directives) { var token = peek(); if (S.token.raw.indexOf("\\") == -1 && (token.nlb || is_token(token, "eof") || is_token(token, "punc", ";") || is_token(token, "punc", "}"))) { S.input.add_directive(S.token.value); } else { S.in_directives = false; } } var dir = S.in_directives, stat = simple_statement(); return dir ? new AST_Directive(stat.body) : stat; case "num": case "regexp": case "operator": case "atom": return simple_statement(); case "name": return is_token(peek(), "punc", ":") ? labeled_statement() : simple_statement(); case "punc": switch (S.token.value) { case "{": return new AST_BlockStatement({ start : S.token, body : block_(), end : prev() }); case "[": case "(": return simple_statement(); case ";": S.in_directives = false; next(); return new AST_EmptyStatement(); default: unexpected(); } case "keyword": switch (S.token.value) { case "break": next(); return break_cont(AST_Break); case "continue": next(); return break_cont(AST_Continue); case "debugger": next(); semicolon(); return new AST_Debugger(); case "do": next(); var body = in_loop(statement); expect_token("keyword", "while"); var condition = parenthesised(); semicolon(true); return new AST_Do({ body : body, condition : condition }); case "while": next(); return new AST_While({ condition : parenthesised(), body : in_loop(statement) }); case "for": next(); return for_(); case "function": next(); return function_(AST_Defun); case "if": next(); return if_(); case "return": if (S.in_function == 0 && !options.bare_returns) croak("'return' outside of function"); next(); var value = null; if (is("punc", ";")) { next(); } else if (!can_insert_semicolon()) { value = expression(true); semicolon(); } return new AST_Return({ value: value }); case "switch": next(); return new AST_Switch({ expression : parenthesised(), body : in_loop(switch_body_) }); case "throw": next(); if (S.token.nlb) croak("Illegal newline after 'throw'"); var value = expression(true); semicolon(); return new AST_Throw({ value: value }); case "try": next(); return try_(); case "var": next(); var node = var_(); semicolon(); return node; case "const": next(); var node = const_(); semicolon(); return node; case "with": if (S.input.has_directive("use strict")) { croak("Strict mode may not include a with statement"); } next(); return new AST_With({ expression : parenthesised(), body : statement() }); } } unexpected(); }); function labeled_statement() { var label = as_symbol(AST_Label); if (find_if(function(l){ return l.name == label.name }, S.labels)) { // ECMA-262, 12.12: An ECMAScript program is considered // syntactically incorrect if it contains a // LabelledStatement that is enclosed by a // LabelledStatement with the same Identifier as label. croak("Label " + label.name + " defined twice"); } expect(":"); S.labels.push(label); var stat = statement(); S.labels.pop(); if (!(stat instanceof AST_IterationStatement)) { // check for `continue` that refers to this label. // those should be reported as syntax errors. // https://github.com/mishoo/UglifyJS2/issues/287 label.references.forEach(function(ref){ if (ref instanceof AST_Continue) { ref = ref.label.start; croak("Continue label `" + label.name + "` refers to non-IterationStatement.", ref.line, ref.col, ref.pos); } }); } return new AST_LabeledStatement({ body: stat, label: label }); }; function simple_statement(tmp) { return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); }; function break_cont(type) { var label = null, ldef; if (!can_insert_semicolon()) { label = as_symbol(AST_LabelRef, true); } if (label != null) { ldef = find_if(function(l){ return l.name == label.name }, S.labels); if (!ldef) croak("Undefined label " + label.name); label.thedef = ldef; } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch"); semicolon(); var stat = new type({ label: label }); if (ldef) ldef.references.push(stat); return stat; }; function for_() { expect("("); var init = null; if (!is("punc", ";")) { init = is("keyword", "var") ? (next(), var_(true)) : expression(true, true); if (is("operator", "in")) { if (init instanceof AST_Var && init.definitions.length > 1) croak("Only one variable declaration allowed in for..in loop"); next(); return for_in(init); } } return regular_for(init); }; function regular_for(init) { expect(";"); var test = is("punc", ";") ? null : expression(true); expect(";"); var step = is("punc", ")") ? null : expression(true); expect(")"); return new AST_For({ init : init, condition : test, step : step, body : in_loop(statement) }); }; function for_in(init) { var lhs = init instanceof AST_Var ? init.definitions[0].name : null; var obj = expression(true); expect(")"); return new AST_ForIn({ init : init, name : lhs, object : obj, body : in_loop(statement) }); }; var function_ = function(ctor) { var in_statement = ctor === AST_Defun; var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; if (in_statement && !name) unexpected(); expect("("); return new ctor({ name: name, argnames: (function(first, a){ while (!is("punc", ")")) { if (first) first = false; else expect(","); a.push(as_symbol(AST_SymbolFunarg)); } next(); return a; })(true, []), body: (function(loop, labels){ ++S.in_function; S.in_directives = true; S.input.push_directives_stack(); S.in_loop = 0; S.labels = []; var a = block_(); S.input.pop_directives_stack(); --S.in_function; S.in_loop = loop; S.labels = labels; return a; })(S.in_loop, S.labels) }); }; function if_() { var cond = parenthesised(), body = statement(), belse = null; if (is("keyword", "else")) { next(); belse = statement(); } return new AST_If({ condition : cond, body : body, alternative : belse }); }; function block_() { expect("{"); var a = []; while (!is("punc", "}")) { if (is("eof")) unexpected(); a.push(statement()); } next(); return a; }; function switch_body_() { expect("{"); var a = [], cur = null, branch = null, tmp; while (!is("punc", "}")) { if (is("eof")) unexpected(); if (is("keyword", "case")) { if (branch) branch.end = prev(); cur = []; branch = new AST_Case({ start : (tmp = S.token, next(), tmp), expression : expression(true), body : cur }); a.push(branch); expect(":"); } else if (is("keyword", "default")) { if (branch) branch.end = prev(); cur = []; branch = new AST_Default({ start : (tmp = S.token, next(), expect(":"), tmp), body : cur }); a.push(branch); } else { if (!cur) unexpected(); cur.push(statement()); } } if (branch) branch.end = prev(); next(); return a; }; function try_() { var body = block_(), bcatch = null, bfinally = null; if (is("keyword", "catch")) { var start = S.token; next(); expect("("); var name = as_symbol(AST_SymbolCatch); expect(")"); bcatch = new AST_Catch({ start : start, argname : name, body : block_(), end : prev() }); } if (is("keyword", "finally")) { var start = S.token; next(); bfinally = new AST_Finally({ start : start, body : block_(), end : prev() }); } if (!bcatch && !bfinally) croak("Missing catch/finally blocks"); return new AST_Try({ body : body, bcatch : bcatch, bfinally : bfinally }); }; function vardefs(no_in, in_const) { var a = []; for (;;) { a.push(new AST_VarDef({ start : S.token, name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), value : is("operator", "=") ? (next(), expression(false, no_in)) : null, end : prev() })); if (!is("punc", ",")) break; next(); } return a; }; var var_ = function(no_in) { return new AST_Var({ start : prev(), definitions : vardefs(no_in, false), end : prev() }); }; var const_ = function() { return new AST_Const({ start : prev(), definitions : vardefs(false, true), end : prev() }); }; var new_ = function(allow_calls) { var start = S.token; expect_token("operator", "new"); var newexp = expr_atom(false), args; if (is("punc", "(")) { next(); args = expr_list(")"); } else { args = []; } return subscripts(new AST_New({ start : start, expression : newexp, args : args, end : prev() }), allow_calls); }; function as_atom_node() { var tok = S.token, ret; switch (tok.type) { case "name": case "keyword": ret = _make_symbol(AST_SymbolRef); break; case "num": ret = new AST_Number({ start: tok, end: tok, value: tok.value }); break; case "string": ret = new AST_String({ start : tok, end : tok, value : tok.value, quote : tok.quote }); break; case "regexp": ret = new AST_RegExp({ start: tok, end: tok, value: tok.value }); break; case "atom": switch (tok.value) { case "false": ret = new AST_False({ start: tok, end: tok }); break; case "true": ret = new AST_True({ start: tok, end: tok }); break; case "null": ret = new AST_Null({ start: tok, end: tok }); break; } break; case "operator": if (!is_identifier_string(tok.value)) { croak("Invalid getter/setter name: " + tok.value, tok.line, tok.col, tok.pos); } ret = _make_symbol(AST_SymbolRef); break; } next(); return ret; }; var expr_atom = function(allow_calls) { if (is("operator", "new")) { return new_(allow_calls); } var start = S.token; if (is("punc")) { switch (start.value) { case "(": next(); var ex = expression(true); ex.start = start; ex.end = S.token; expect(")"); return subscripts(ex, allow_calls); case "[": return subscripts(array_(), allow_calls); case "{": return subscripts(object_(), allow_calls); } unexpected(); } if (is("keyword", "function")) { next(); var func = function_(AST_Function); func.start = start; func.end = prev(); return subscripts(func, allow_calls); } if (ATOMIC_START_TOKEN[S.token.type]) { return subscripts(as_atom_node(), allow_calls); } unexpected(); }; function expr_list(closing, allow_trailing_comma, allow_empty) { var first = true, a = []; while (!is("punc", closing)) { if (first) first = false; else expect(","); if (allow_trailing_comma && is("punc", closing)) break; if (is("punc", ",") && allow_empty) { a.push(new AST_Hole({ start: S.token, end: S.token })); } else { a.push(expression(false)); } } next(); return a; }; var array_ = embed_tokens(function() { expect("["); return new AST_Array({ elements: expr_list("]", !options.strict, true) }); }); var create_accessor = embed_tokens(function() { return function_(AST_Accessor); }); var object_ = embed_tokens(function() { expect("{"); var first = true, a = []; while (!is("punc", "}")) { if (first) first = false; else expect(","); if (!options.strict && is("punc", "}")) // allow trailing comma break; var start = S.token; var type = start.type; var name = as_property_name(); if (type == "name" && !is("punc", ":")) { var key = new AST_SymbolAccessor({ start: S.token, name: as_property_name(), end: prev() }); if (name == "get") { a.push(new AST_ObjectGetter({ start : start, key : key, value : create_accessor(), end : prev() })); continue; } if (name == "set") { a.push(new AST_ObjectSetter({ start : start, key : key, value : create_accessor(), end : prev() })); continue; } } expect(":"); a.push(new AST_ObjectKeyVal({ start : start, quote : start.quote, key : name, value : expression(false), end : prev() })); } next(); return new AST_Object({ properties: a }); }); function as_property_name() { var tmp = S.token; switch (tmp.type) { case "operator": if (!KEYWORDS(tmp.value)) unexpected(); case "num": case "string": case "name": case "keyword": case "atom": next(); return tmp.value; default: unexpected(); } }; function as_name() { var tmp = S.token; if (tmp.type != "name") unexpected(); next(); return tmp.value; }; function _make_symbol(type) { var name = S.token.value; return new (name == "this" ? AST_This : type)({ name : String(name), start : S.token, end : S.token }); }; function as_symbol(type, noerror) { if (!is("name")) { if (!noerror) croak("Name expected"); return null; } var sym = _make_symbol(type); next(); return sym; }; var subscripts = function(expr, allow_calls) { var start = expr.start; if (is("punc", ".")) { next(); return subscripts(new AST_Dot({ start : start, expression : expr, property : as_name(), end : prev() }), allow_calls); } if (is("punc", "[")) { next(); var prop = expression(true); expect("]"); return subscripts(new AST_Sub({ start : start, expression : expr, property : prop, end : prev() }), allow_calls); } if (allow_calls && is("punc", "(")) { next(); return subscripts(new AST_Call({ start : start, expression : expr, args : expr_list(")"), end : prev() }), true); } return expr; }; var maybe_unary = function(allow_calls) { var start = S.token; if (is("operator") && UNARY_PREFIX(start.value)) { next(); handle_regexp(); var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls)); ex.start = start; ex.end = prev(); return ex; } var val = expr_atom(allow_calls); while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { val = make_unary(AST_UnaryPostfix, S.token, val); val.start = start; val.end = S.token; next(); } return val; }; function make_unary(ctor, token, expr) { var op = token.value; if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator", token.line, token.col, token.pos); return new ctor({ operator: op, expression: expr }); }; var expr_op = function(left, min_prec, no_in) { var op = is("operator") ? S.token.value : null; if (op == "in" && no_in) op = null; var prec = op != null ? PRECEDENCE[op] : null; if (prec != null && prec > min_prec) { next(); var right = expr_op(maybe_unary(true), prec, no_in); return expr_op(new AST_Binary({ start : left.start, left : left, operator : op, right : right, end : right.end }), min_prec, no_in); } return left; }; function expr_ops(no_in) { return expr_op(maybe_unary(true), 0, no_in); }; var maybe_conditional = function(no_in) { var start = S.token; var expr = expr_ops(no_in); if (is("operator", "?")) { next(); var yes = expression(false); expect(":"); return new AST_Conditional({ start : start, condition : expr, consequent : yes, alternative : expression(false, no_in), end : prev() }); } return expr; }; function is_assignable(expr) { if (options.cli) return true; return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef; }; var maybe_assign = function(no_in) { var start = S.token; var left = maybe_conditional(no_in), val = S.token.value; if (is("operator") && ASSIGNMENT(val)) { if (is_assignable(left)) { next(); return new AST_Assign({ start : start, left : left, operator : val, right : maybe_assign(no_in), end : prev() }); } croak("Invalid assignment"); } return left; }; var expression = function(commas, no_in) { var start = S.token; var expr = maybe_assign(no_in); if (commas && is("punc", ",")) { next(); return new AST_Seq({ start : start, car : expr, cdr : expression(true, no_in), end : peek() }); } return expr; }; function in_loop(cont) { ++S.in_loop; var ret = cont(); --S.in_loop; return ret; }; if (options.expression) { return expression(true); } return (function(){ var start = S.token; var body = []; S.input.push_directives_stack(); while (!is("eof")) body.push(statement()); S.input.pop_directives_stack(); var end = prev(); var toplevel = options.toplevel; if (toplevel) { toplevel.body = toplevel.body.concat(body); toplevel.end = end; } else { toplevel = new AST_Toplevel({ start: start, body: body, end: end }); } return toplevel; })(); }; UglifyJS2-2.8.29/lib/propmangle.js000066400000000000000000000212771312030606600166500ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; function find_builtins() { // NaN will be included due to Number.NaN var a = [ "null", "true", "false", "Infinity", "-Infinity", "undefined", ]; [ Object, Array, Function, Number, String, Boolean, Error, Math, Date, RegExp ].forEach(function(ctor){ Object.getOwnPropertyNames(ctor).map(add); if (ctor.prototype) { Object.getOwnPropertyNames(ctor.prototype).map(add); } }); function add(name) { push_uniq(a, name); } return a; } function mangle_properties(ast, options) { options = defaults(options, { cache: null, debug: false, ignore_quoted: false, only_cache: false, regex: null, reserved: null, }); var reserved = options.reserved; if (reserved == null) reserved = find_builtins(); var cache = options.cache; if (cache == null) { cache = { cname: -1, props: new Dictionary() }; } var regex = options.regex; var ignore_quoted = options.ignore_quoted; // note debug is either false (disabled), or a string of the debug suffix to use (enabled). // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true' // the same as passing an empty string. var debug = (options.debug !== false); var debug_name_suffix; if (debug) { debug_name_suffix = (options.debug === true ? "" : options.debug); } var names_to_mangle = []; var unmangleable = []; var ignored = {}; // step 1: find candidates to mangle ast.walk(new TreeWalker(function(node){ if (node instanceof AST_ObjectKeyVal) { add(node.key, ignore_quoted && node.quote); } else if (node instanceof AST_ObjectProperty) { // setter or getter, since KeyVal is handled above add(node.key.name); } else if (node instanceof AST_Dot) { add(node.property); } else if (node instanceof AST_Sub) { addStrings(node.property, ignore_quoted); } })); // step 2: transform the tree, renaming properties return ast.transform(new TreeTransformer(function(node){ if (node instanceof AST_ObjectKeyVal) { if (!(ignore_quoted && node.quote)) node.key = mangle(node.key); } else if (node instanceof AST_ObjectProperty) { // setter or getter node.key.name = mangle(node.key.name); } else if (node instanceof AST_Dot) { node.property = mangle(node.property); } else if (node instanceof AST_Sub) { if (!ignore_quoted) node.property = mangleStrings(node.property); } // else if (node instanceof AST_String) { // if (should_mangle(node.value)) { // AST_Node.warn( // "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", { // file : node.start.file, // line : node.start.line, // col : node.start.col, // prop : node.value // } // ); // } // } })); // only function declarations after this line function can_mangle(name) { if (unmangleable.indexOf(name) >= 0) return false; if (reserved.indexOf(name) >= 0) return false; if (options.only_cache) { return cache.props.has(name); } if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; return true; } function should_mangle(name) { if (ignore_quoted && name in ignored) return false; if (regex && !regex.test(name)) return false; if (reserved.indexOf(name) >= 0) return false; return cache.props.has(name) || names_to_mangle.indexOf(name) >= 0; } function add(name, ignore) { if (ignore) { ignored[name] = true; return; } if (can_mangle(name)) push_uniq(names_to_mangle, name); if (!should_mangle(name)) { push_uniq(unmangleable, name); } } function mangle(name) { if (!should_mangle(name)) { return name; } var mangled = cache.props.get(name); if (!mangled) { if (debug) { // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; if (can_mangle(debug_mangled) && !(ignore_quoted && debug_mangled in ignored)) { mangled = debug_mangled; } } // either debug mode is off, or it is on and we could not use the mangled name if (!mangled) { // note can_mangle() does not check if the name collides with the 'ignored' set // (filled with quoted properties when ignore_quoted set). Make sure we add this // check so we don't collide with a quoted name. do { mangled = base54(++cache.cname); } while (!can_mangle(mangled) || (ignore_quoted && mangled in ignored)); } cache.props.set(name, mangled); } return mangled; } function addStrings(node, ignore) { var out = {}; try { (function walk(node){ node.walk(new TreeWalker(function(node){ if (node instanceof AST_Seq) { walk(node.cdr); return true; } if (node instanceof AST_String) { add(node.value, ignore); return true; } if (node instanceof AST_Conditional) { walk(node.consequent); walk(node.alternative); return true; } throw out; })); })(node); } catch(ex) { if (ex !== out) throw ex; } } function mangleStrings(node) { return node.transform(new TreeTransformer(function(node){ if (node instanceof AST_Seq) { node.cdr = mangleStrings(node.cdr); } else if (node instanceof AST_String) { node.value = mangle(node.value); } else if (node instanceof AST_Conditional) { node.consequent = mangleStrings(node.consequent); node.alternative = mangleStrings(node.alternative); } return node; })); } } UglifyJS2-2.8.29/lib/scope.js000066400000000000000000000556731312030606600156240ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; function SymbolDef(scope, index, orig) { this.name = orig.name; this.orig = [ orig ]; this.scope = scope; this.references = []; this.global = false; this.mangled_name = null; this.undeclared = false; this.index = index; this.id = SymbolDef.next_id++; }; SymbolDef.next_id = 1; SymbolDef.prototype = { unmangleable: function(options) { if (!options) options = {}; return (this.global && !options.toplevel) || this.undeclared || (!options.eval && (this.scope.uses_eval || this.scope.uses_with)) || (options.keep_fnames && (this.orig[0] instanceof AST_SymbolLambda || this.orig[0] instanceof AST_SymbolDefun)); }, mangle: function(options) { var cache = options.cache && options.cache.props; if (this.global && cache && cache.has(this.name)) { this.mangled_name = cache.get(this.name); } else if (!this.mangled_name && !this.unmangleable(options)) { var s = this.scope; var sym = this.orig[0]; if (!options.screw_ie8 && sym instanceof AST_SymbolLambda) s = s.parent_scope; var def; if (this.defun && (def = this.defun.variables.get(this.name))) { this.mangled_name = def.mangled_name || def.name; } else this.mangled_name = s.next_mangled(options, this); if (this.global && cache) { cache.set(this.name, this.mangled_name); } } } }; AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ options = defaults(options, { cache: null, screw_ie8: true, }); // pass 1: setup scope chaining and handle definitions var self = this; var scope = self.parent_scope = null; var labels = new Dictionary(); var defun = null; var tw = new TreeWalker(function(node, descend){ if (node instanceof AST_Catch) { var save_scope = scope; scope = new AST_Scope(node); scope.init_scope_vars(save_scope); descend(); scope = save_scope; return true; } if (node instanceof AST_Scope) { node.init_scope_vars(scope); var save_scope = scope; var save_defun = defun; var save_labels = labels; defun = scope = node; labels = new Dictionary(); descend(); scope = save_scope; defun = save_defun; labels = save_labels; return true; // don't descend again in TreeWalker } if (node instanceof AST_LabeledStatement) { var l = node.label; if (labels.has(l.name)) { throw new Error(string_template("Label {name} defined twice", l)); } labels.set(l.name, l); descend(); labels.del(l.name); return true; // no descend again } if (node instanceof AST_With) { for (var s = scope; s; s = s.parent_scope) s.uses_with = true; return; } if (node instanceof AST_Symbol) { node.scope = scope; } if (node instanceof AST_Label) { node.thedef = node; node.references = []; } if (node instanceof AST_SymbolLambda) { defun.def_function(node); } else if (node instanceof AST_SymbolDefun) { // Careful here, the scope where this should be defined is // the parent scope. The reason is that we enter a new // scope when we encounter the AST_Defun node (which is // instanceof AST_Scope) but we get to the symbol a bit // later. (node.scope = defun.parent_scope).def_function(node); } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) { defun.def_variable(node); if (defun !== scope) { node.mark_enclosed(options); var def = scope.find_variable(node); if (node.thedef !== def) { node.thedef = def; node.reference(options); } } } else if (node instanceof AST_SymbolCatch) { scope.def_variable(node).defun = defun; } else if (node instanceof AST_LabelRef) { var sym = labels.get(node.name); if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { name: node.name, line: node.start.line, col: node.start.col })); node.thedef = sym; } }); self.walk(tw); // pass 2: find back references and eval var func = null; var globals = self.globals = new Dictionary(); var tw = new TreeWalker(function(node, descend){ if (node instanceof AST_Lambda) { var prev_func = func; func = node; descend(); func = prev_func; return true; } if (node instanceof AST_LoopControl && node.label) { node.label.thedef.references.push(node); return true; } if (node instanceof AST_SymbolRef) { var name = node.name; if (name == "eval" && tw.parent() instanceof AST_Call) { for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) { s.uses_eval = true; } } var sym = node.scope.find_variable(name); if (node.scope instanceof AST_Lambda && name == "arguments") { node.scope.uses_arguments = true; } if (!sym) { sym = self.def_global(node); } node.thedef = sym; node.reference(options); return true; } }); self.walk(tw); // pass 3: fix up any scoping issue with IE8 if (!options.screw_ie8) { self.walk(new TreeWalker(function(node, descend) { if (node instanceof AST_SymbolCatch) { var name = node.name; var refs = node.thedef.references; var scope = node.thedef.defun; var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node); refs.forEach(function(ref) { ref.thedef = def; ref.reference(options); }); node.thedef = def; return true; } })); } if (options.cache) { this.cname = options.cache.cname; } }); AST_Toplevel.DEFMETHOD("def_global", function(node){ var globals = this.globals, name = node.name; if (globals.has(name)) { return globals.get(name); } else { var g = new SymbolDef(this, globals.size(), node); g.undeclared = true; g.global = true; globals.set(name, g); return g; } }); AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){ this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` this.parent_scope = parent_scope; // the parent scope this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes this.cname = -1; // the current index for mangling functions/variables }); AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Scope.prototype.init_scope_vars.apply(this, arguments); this.uses_arguments = false; this.def_variable(new AST_SymbolVar({ name: "arguments", start: this.start, end: this.end })); }); AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { var def = this.definition(); var s = this.scope; while (s) { push_uniq(s.enclosed, def); if (options.keep_fnames) { s.functions.each(function(d) { push_uniq(def.scope.enclosed, d); }); } if (s === def.scope) break; s = s.parent_scope; } }); AST_Symbol.DEFMETHOD("reference", function(options) { this.definition().references.push(this); this.mark_enclosed(options); }); AST_Scope.DEFMETHOD("find_variable", function(name){ if (name instanceof AST_Symbol) name = name.name; return this.variables.get(name) || (this.parent_scope && this.parent_scope.find_variable(name)); }); AST_Scope.DEFMETHOD("def_function", function(symbol){ this.functions.set(symbol.name, this.def_variable(symbol)); }); AST_Scope.DEFMETHOD("def_variable", function(symbol){ var def; if (!this.variables.has(symbol.name)) { def = new SymbolDef(this, this.variables.size(), symbol); this.variables.set(symbol.name, def); def.global = !this.parent_scope; } else { def = this.variables.get(symbol.name); def.orig.push(symbol); } return symbol.thedef = def; }); AST_Scope.DEFMETHOD("next_mangled", function(options){ var ext = this.enclosed; out: while (true) { var m = base54(++this.cname); if (!is_identifier(m)) continue; // skip over "do" // https://github.com/mishoo/UglifyJS2/issues/242 -- do not // shadow a name excepted from mangling. if (options.except.indexOf(m) >= 0) continue; // we must ensure that the mangled name does not shadow a name // from some parent scope that is referenced in this or in // inner scopes. for (var i = ext.length; --i >= 0;) { var sym = ext[i]; var name = sym.mangled_name || (sym.unmangleable(options) && sym.name); if (m == name) continue out; } return m; } }); AST_Function.DEFMETHOD("next_mangled", function(options, def){ // #179, #326 // in Safari strict mode, something like (function x(x){...}) is a syntax error; // a function expression's argument cannot shadow the function expression's name var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition(); // the function's mangled_name is null when keep_fnames is true var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null; while (true) { var name = AST_Lambda.prototype.next_mangled.call(this, options, def); if (!tricky_name || tricky_name != name) return name; } }); AST_Symbol.DEFMETHOD("unmangleable", function(options){ return this.definition().unmangleable(options); }); // labels are always mangleable AST_Label.DEFMETHOD("unmangleable", function(){ return false; }); AST_Symbol.DEFMETHOD("unreferenced", function(){ return this.definition().references.length == 0 && !(this.scope.uses_eval || this.scope.uses_with); }); AST_Symbol.DEFMETHOD("undeclared", function(){ return this.definition().undeclared; }); AST_LabelRef.DEFMETHOD("undeclared", function(){ return false; }); AST_Label.DEFMETHOD("undeclared", function(){ return false; }); AST_Symbol.DEFMETHOD("definition", function(){ return this.thedef; }); AST_Symbol.DEFMETHOD("global", function(){ return this.definition().global; }); AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ return defaults(options, { eval : false, except : [], keep_fnames : false, screw_ie8 : true, sort : false, // Ignored. Flag retained for backwards compatibility. toplevel : false, }); }); AST_Toplevel.DEFMETHOD("mangle_names", function(options){ options = this._default_mangler_options(options); // Never mangle arguments options.except.push('arguments'); // We only need to mangle declaration nodes. Special logic wired // into the code generator will display the mangled name if it's // present (and for AST_SymbolRef-s it'll use the mangled name of // the AST_SymbolDeclaration that it points to). var lname = -1; var to_mangle = []; if (options.cache) { this.globals.each(function(symbol){ if (options.except.indexOf(symbol.name) < 0) { to_mangle.push(symbol); } }); } var tw = new TreeWalker(function(node, descend){ if (node instanceof AST_LabeledStatement) { // lname is incremented when we get to the AST_Label var save_nesting = lname; descend(); lname = save_nesting; return true; // don't descend again in TreeWalker } if (node instanceof AST_Scope) { var p = tw.parent(), a = []; node.variables.each(function(symbol){ if (options.except.indexOf(symbol.name) < 0) { a.push(symbol); } }); to_mangle.push.apply(to_mangle, a); return; } if (node instanceof AST_Label) { var name; do name = base54(++lname); while (!is_identifier(name)); node.mangled_name = name; return true; } if (options.screw_ie8 && node instanceof AST_SymbolCatch) { to_mangle.push(node.definition()); return; } }); this.walk(tw); to_mangle.forEach(function(def){ def.mangle(options) }); if (options.cache) { options.cache.cname = this.cname; } }); AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ options = this._default_mangler_options(options); var tw = new TreeWalker(function(node){ if (node instanceof AST_Constant) base54.consider(node.print_to_string()); else if (node instanceof AST_Return) base54.consider("return"); else if (node instanceof AST_Throw) base54.consider("throw"); else if (node instanceof AST_Continue) base54.consider("continue"); else if (node instanceof AST_Break) base54.consider("break"); else if (node instanceof AST_Debugger) base54.consider("debugger"); else if (node instanceof AST_Directive) base54.consider(node.value); else if (node instanceof AST_While) base54.consider("while"); else if (node instanceof AST_Do) base54.consider("do while"); else if (node instanceof AST_If) { base54.consider("if"); if (node.alternative) base54.consider("else"); } else if (node instanceof AST_Var) base54.consider("var"); else if (node instanceof AST_Const) base54.consider("const"); else if (node instanceof AST_Lambda) base54.consider("function"); else if (node instanceof AST_For) base54.consider("for"); else if (node instanceof AST_ForIn) base54.consider("for in"); else if (node instanceof AST_Switch) base54.consider("switch"); else if (node instanceof AST_Case) base54.consider("case"); else if (node instanceof AST_Default) base54.consider("default"); else if (node instanceof AST_With) base54.consider("with"); else if (node instanceof AST_ObjectSetter) base54.consider("set" + node.key); else if (node instanceof AST_ObjectGetter) base54.consider("get" + node.key); else if (node instanceof AST_ObjectKeyVal) base54.consider(node.key); else if (node instanceof AST_New) base54.consider("new"); else if (node instanceof AST_This) base54.consider("this"); else if (node instanceof AST_Try) base54.consider("try"); else if (node instanceof AST_Catch) base54.consider("catch"); else if (node instanceof AST_Finally) base54.consider("finally"); else if (node instanceof AST_Symbol && node.unmangleable(options)) base54.consider(node.name); else if (node instanceof AST_Unary || node instanceof AST_Binary) base54.consider(node.operator); else if (node instanceof AST_Dot) base54.consider(node.property); }); this.walk(tw); base54.sort(); }); var base54 = (function() { var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; var chars, frequency; function reset() { frequency = Object.create(null); chars = string.split("").map(function(ch){ return ch.charCodeAt(0) }); chars.forEach(function(ch){ frequency[ch] = 0 }); } base54.consider = function(str){ for (var i = str.length; --i >= 0;) { var code = str.charCodeAt(i); if (code in frequency) ++frequency[code]; } }; base54.sort = function() { chars = mergeSort(chars, function(a, b){ if (is_digit(a) && !is_digit(b)) return 1; if (is_digit(b) && !is_digit(a)) return -1; return frequency[b] - frequency[a]; }); }; base54.reset = reset; reset(); base54.get = function(){ return chars }; base54.freq = function(){ return frequency }; function base54(num) { var ret = "", base = 54; num++; do { num--; ret += String.fromCharCode(chars[num % base]); num = Math.floor(num / base); base = 64; } while (num > 0); return ret; }; return base54; })(); AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ options = defaults(options, { assign_to_global : true, eval : true, func_arguments : true, nested_defuns : true, undeclared : false, // this makes a lot of noise unreferenced : true, }); var tw = new TreeWalker(function(node){ if (options.undeclared && node instanceof AST_SymbolRef && node.undeclared()) { // XXX: this also warns about JS standard names, // i.e. Object, Array, parseInt etc. Should add a list of // exceptions. AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { name: node.name, file: node.start.file, line: node.start.line, col: node.start.col }); } if (options.assign_to_global) { var sym = null; if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) sym = node.left; else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) sym = node.init; if (sym && (sym.undeclared() || (sym.global() && sym.scope !== sym.definition().scope))) { AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", name: sym.name, file: sym.start.file, line: sym.start.line, col: sym.start.col }); } } if (options.eval && node instanceof AST_SymbolRef && node.undeclared() && node.name == "eval") { AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); } if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) && !(node instanceof AST_SymbolCatch) && node.unreferenced()) { AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { type: node instanceof AST_Label ? "Label" : "Symbol", name: node.name, file: node.start.file, line: node.start.line, col: node.start.col }); } if (options.func_arguments && node instanceof AST_Lambda && node.uses_arguments) { AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { name: node.name ? node.name.name : "anonymous", file: node.start.file, line: node.start.line, col: node.start.col }); } if (options.nested_defuns && node instanceof AST_Defun && !(tw.parent() instanceof AST_Scope)) { AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", { name: node.name.name, type: tw.parent().TYPE, file: node.start.file, line: node.start.line, col: node.start.col }); } }); this.walk(tw); }); UglifyJS2-2.8.29/lib/sourcemap.js000066400000000000000000000070741312030606600165010ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; // a small wrapper around fitzgen's source-map library function SourceMap(options) { options = defaults(options, { file : null, root : null, orig : null, orig_line_diff : 0, dest_line_diff : 0, }); var generator = new MOZ_SourceMap.SourceMapGenerator({ file : options.file, sourceRoot : options.root }); var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig); if (orig_map && Array.isArray(options.orig.sources)) { orig_map._sources.toArray().forEach(function(source) { var sourceContent = orig_map.sourceContentFor(source, true); if (sourceContent) { generator.setSourceContent(source, sourceContent); } }); } function add(source, gen_line, gen_col, orig_line, orig_col, name) { if (orig_map) { var info = orig_map.originalPositionFor({ line: orig_line, column: orig_col }); if (info.source === null) { return; } source = info.source; orig_line = info.line; orig_col = info.column; name = info.name || name; } generator.addMapping({ generated : { line: gen_line + options.dest_line_diff, column: gen_col }, original : { line: orig_line + options.orig_line_diff, column: orig_col }, source : source, name : name }); }; return { add : add, get : function() { return generator }, toString : function() { return JSON.stringify(generator.toJSON()); } }; }; UglifyJS2-2.8.29/lib/transform.js000066400000000000000000000154321312030606600165130ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; // Tree transformer helpers. function TreeTransformer(before, after) { TreeWalker.call(this); this.before = before; this.after = after; } TreeTransformer.prototype = new TreeWalker; (function(undefined){ function _(node, descend) { node.DEFMETHOD("transform", function(tw, in_list){ var x, y; tw.push(this); if (tw.before) x = tw.before(this, descend, in_list); if (x === undefined) { if (!tw.after) { x = this; descend(x, tw); } else { tw.stack[tw.stack.length - 1] = x = this; descend(x, tw); y = tw.after(x, in_list); if (y !== undefined) x = y; } } tw.pop(this); return x; }); }; function do_list(list, tw) { return MAP(list, function(node){ return node.transform(tw, true); }); }; _(AST_Node, noop); _(AST_LabeledStatement, function(self, tw){ self.label = self.label.transform(tw); self.body = self.body.transform(tw); }); _(AST_SimpleStatement, function(self, tw){ self.body = self.body.transform(tw); }); _(AST_Block, function(self, tw){ self.body = do_list(self.body, tw); }); _(AST_DWLoop, function(self, tw){ self.condition = self.condition.transform(tw); self.body = self.body.transform(tw); }); _(AST_For, function(self, tw){ if (self.init) self.init = self.init.transform(tw); if (self.condition) self.condition = self.condition.transform(tw); if (self.step) self.step = self.step.transform(tw); self.body = self.body.transform(tw); }); _(AST_ForIn, function(self, tw){ self.init = self.init.transform(tw); self.object = self.object.transform(tw); self.body = self.body.transform(tw); }); _(AST_With, function(self, tw){ self.expression = self.expression.transform(tw); self.body = self.body.transform(tw); }); _(AST_Exit, function(self, tw){ if (self.value) self.value = self.value.transform(tw); }); _(AST_LoopControl, function(self, tw){ if (self.label) self.label = self.label.transform(tw); }); _(AST_If, function(self, tw){ self.condition = self.condition.transform(tw); self.body = self.body.transform(tw); if (self.alternative) self.alternative = self.alternative.transform(tw); }); _(AST_Switch, function(self, tw){ self.expression = self.expression.transform(tw); self.body = do_list(self.body, tw); }); _(AST_Case, function(self, tw){ self.expression = self.expression.transform(tw); self.body = do_list(self.body, tw); }); _(AST_Try, function(self, tw){ self.body = do_list(self.body, tw); if (self.bcatch) self.bcatch = self.bcatch.transform(tw); if (self.bfinally) self.bfinally = self.bfinally.transform(tw); }); _(AST_Catch, function(self, tw){ self.argname = self.argname.transform(tw); self.body = do_list(self.body, tw); }); _(AST_Definitions, function(self, tw){ self.definitions = do_list(self.definitions, tw); }); _(AST_VarDef, function(self, tw){ self.name = self.name.transform(tw); if (self.value) self.value = self.value.transform(tw); }); _(AST_Lambda, function(self, tw){ if (self.name) self.name = self.name.transform(tw); self.argnames = do_list(self.argnames, tw); self.body = do_list(self.body, tw); }); _(AST_Call, function(self, tw){ self.expression = self.expression.transform(tw); self.args = do_list(self.args, tw); }); _(AST_Seq, function(self, tw){ self.car = self.car.transform(tw); self.cdr = self.cdr.transform(tw); }); _(AST_Dot, function(self, tw){ self.expression = self.expression.transform(tw); }); _(AST_Sub, function(self, tw){ self.expression = self.expression.transform(tw); self.property = self.property.transform(tw); }); _(AST_Unary, function(self, tw){ self.expression = self.expression.transform(tw); }); _(AST_Binary, function(self, tw){ self.left = self.left.transform(tw); self.right = self.right.transform(tw); }); _(AST_Conditional, function(self, tw){ self.condition = self.condition.transform(tw); self.consequent = self.consequent.transform(tw); self.alternative = self.alternative.transform(tw); }); _(AST_Array, function(self, tw){ self.elements = do_list(self.elements, tw); }); _(AST_Object, function(self, tw){ self.properties = do_list(self.properties, tw); }); _(AST_ObjectProperty, function(self, tw){ self.value = self.value.transform(tw); }); })(); UglifyJS2-2.8.29/lib/utils.js000066400000000000000000000255301312030606600156400ustar00rootroot00000000000000/*********************************************************************** A JavaScript tokenizer / parser / beautifier / compressor. https://github.com/mishoo/UglifyJS2 -------------------------------- (C) --------------------------------- Author: Mihai Bazon http://mihai.bazon.net/blog Distributed under the BSD license: Copyright 2012 (c) Mihai Bazon Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ "use strict"; function array_to_hash(a) { var ret = Object.create(null); for (var i = 0; i < a.length; ++i) ret[a[i]] = true; return ret; }; function slice(a, start) { return Array.prototype.slice.call(a, start || 0); }; function characters(str) { return str.split(""); }; function member(name, array) { return array.indexOf(name) >= 0; }; function find_if(func, array) { for (var i = 0, n = array.length; i < n; ++i) { if (func(array[i])) return array[i]; } }; function repeat_string(str, i) { if (i <= 0) return ""; if (i == 1) return str; var d = repeat_string(str, i >> 1); d += d; if (i & 1) d += str; return d; }; function configure_error_stack(fn) { Object.defineProperty(fn.prototype, "stack", { get: function() { var err = new Error(this.message); err.name = this.name; try { throw err; } catch(e) { return e.stack; } } }); } function DefaultsError(msg, defs) { this.message = msg; this.defs = defs; }; DefaultsError.prototype = Object.create(Error.prototype); DefaultsError.prototype.constructor = DefaultsError; DefaultsError.prototype.name = "DefaultsError"; configure_error_stack(DefaultsError); DefaultsError.croak = function(msg, defs) { throw new DefaultsError(msg, defs); }; function defaults(args, defs, croak) { if (args === true) args = {}; var ret = args || {}; if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) DefaultsError.croak("`" + i + "` is not a supported option", defs); for (var i in defs) if (HOP(defs, i)) { ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; } return ret; }; function merge(obj, ext) { var count = 0; for (var i in ext) if (HOP(ext, i)) { obj[i] = ext[i]; count++; } return count; }; function noop() {} function return_false() { return false; } function return_true() { return true; } function return_this() { return this; } function return_null() { return null; } var MAP = (function(){ function MAP(a, f, backwards) { var ret = [], top = [], i; function doit() { var val = f(a[i], i); var is_last = val instanceof Last; if (is_last) val = val.v; if (val instanceof AtTop) { val = val.v; if (val instanceof Splice) { top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); } else { top.push(val); } } else if (val !== skip) { if (val instanceof Splice) { ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); } else { ret.push(val); } } return is_last; }; if (a instanceof Array) { if (backwards) { for (i = a.length; --i >= 0;) if (doit()) break; ret.reverse(); top.reverse(); } else { for (i = 0; i < a.length; ++i) if (doit()) break; } } else { for (i in a) if (HOP(a, i)) if (doit()) break; } return top.concat(ret); }; MAP.at_top = function(val) { return new AtTop(val) }; MAP.splice = function(val) { return new Splice(val) }; MAP.last = function(val) { return new Last(val) }; var skip = MAP.skip = {}; function AtTop(val) { this.v = val }; function Splice(val) { this.v = val }; function Last(val) { this.v = val }; return MAP; })(); function push_uniq(array, el) { if (array.indexOf(el) < 0) array.push(el); }; function string_template(text, props) { return text.replace(/\{(.+?)\}/g, function(str, p){ return props && props[p]; }); }; function remove(array, el) { for (var i = array.length; --i >= 0;) { if (array[i] === el) array.splice(i, 1); } }; function mergeSort(array, cmp) { if (array.length < 2) return array.slice(); function merge(a, b) { var r = [], ai = 0, bi = 0, i = 0; while (ai < a.length && bi < b.length) { cmp(a[ai], b[bi]) <= 0 ? r[i++] = a[ai++] : r[i++] = b[bi++]; } if (ai < a.length) r.push.apply(r, a.slice(ai)); if (bi < b.length) r.push.apply(r, b.slice(bi)); return r; }; function _ms(a) { if (a.length <= 1) return a; var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); left = _ms(left); right = _ms(right); return merge(left, right); }; return _ms(array); }; function set_difference(a, b) { return a.filter(function(el){ return b.indexOf(el) < 0; }); }; function set_intersection(a, b) { return a.filter(function(el){ return b.indexOf(el) >= 0; }); }; // this function is taken from Acorn [1], written by Marijn Haverbeke // [1] https://github.com/marijnh/acorn function makePredicate(words) { if (!(words instanceof Array)) words = words.split(" "); var f = "", cats = []; out: for (var i = 0; i < words.length; ++i) { for (var j = 0; j < cats.length; ++j) if (cats[j][0].length == words[i].length) { cats[j].push(words[i]); continue out; } cats.push([words[i]]); } function quote(word) { return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) { switch (s) { case "\u2028": return "\\u2028"; case "\u2029": return "\\u2029"; } return s; }); } function compareTo(arr) { if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";"; f += "switch(str){"; for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":"; f += "return true}return false;"; } // When there are more than three length categories, an outer // switch first dispatches on the lengths, to save on comparisons. if (cats.length > 3) { cats.sort(function(a, b) {return b.length - a.length;}); f += "switch(str.length){"; for (var i = 0; i < cats.length; ++i) { var cat = cats[i]; f += "case " + cat[0].length + ":"; compareTo(cat); } f += "}"; // Otherwise, simply generate a flat `switch` statement. } else { compareTo(words); } return new Function("str", f); }; function all(array, predicate) { for (var i = array.length; --i >= 0;) if (!predicate(array[i])) return false; return true; }; function Dictionary() { this._values = Object.create(null); this._size = 0; }; Dictionary.prototype = { set: function(key, val) { if (!this.has(key)) ++this._size; this._values["$" + key] = val; return this; }, add: function(key, val) { if (this.has(key)) { this.get(key).push(val); } else { this.set(key, [ val ]); } return this; }, get: function(key) { return this._values["$" + key] }, del: function(key) { if (this.has(key)) { --this._size; delete this._values["$" + key]; } return this; }, has: function(key) { return ("$" + key) in this._values }, each: function(f) { for (var i in this._values) f(this._values[i], i.substr(1)); }, size: function() { return this._size; }, map: function(f) { var ret = []; for (var i in this._values) ret.push(f(this._values[i], i.substr(1))); return ret; }, toObject: function() { return this._values } }; Dictionary.fromObject = function(obj) { var dict = new Dictionary(); dict._size = merge(dict._values, obj); return dict; }; function HOP(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } // return true if the node at the top of the stack (that means the // innermost node in the current output) is lexically the first in // a statement. function first_in_statement(stack) { var node = stack.parent(-1); for (var i = 0, p; p = stack.parent(i); i++) { if (p instanceof AST_Statement && p.body === node) return true; if ((p instanceof AST_Seq && p.car === node ) || (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) || (p instanceof AST_Dot && p.expression === node ) || (p instanceof AST_Sub && p.expression === node ) || (p instanceof AST_Conditional && p.condition === node ) || (p instanceof AST_Binary && p.left === node ) || (p instanceof AST_UnaryPostfix && p.expression === node )) { node = p; } else { return false; } } } UglifyJS2-2.8.29/package.json000066400000000000000000000021631312030606600156570ustar00rootroot00000000000000{ "name": "uglify-js", "description": "JavaScript parser, mangler/compressor and beautifier toolkit", "homepage": "http://lisperator.net/uglifyjs", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", "version": "2.8.29", "engines": { "node": ">=0.8.0" }, "maintainers": [ "Mihai Bazon (http://lisperator.net/)" ], "repository": { "type": "git", "url": "https://github.com/mishoo/UglifyJS2.git" }, "bugs": { "url": "https://github.com/mishoo/UglifyJS2/issues" }, "main": "tools/node.js", "bin": { "uglifyjs": "bin/uglifyjs" }, "files": [ "bin", "lib", "tools", "LICENSE" ], "dependencies": { "source-map": "~0.5.1", "yargs": "~3.10.0" }, "devDependencies": { "acorn": "~5.0.3", "mocha": "~2.3.4" }, "optionalDependencies": { "uglify-to-browserify": "~1.0.0" }, "browserify": { "transform": [ "uglify-to-browserify" ] }, "scripts": { "test": "node test/run-tests.js" }, "keywords": ["uglify", "uglify-js", "minify", "minifier"] } UglifyJS2-2.8.29/test/000077500000000000000000000000001312030606600143465ustar00rootroot00000000000000UglifyJS2-2.8.29/test/benchmark.js000066400000000000000000000051361312030606600166430ustar00rootroot00000000000000#! /usr/bin/env node // -*- js -*- "use strict"; var createHash = require("crypto").createHash; var fork = require("child_process").fork; var args = process.argv.slice(2); if (!args.length) { args.push("-mc", "warnings=false"); } args.push("--stats"); var urls = [ "https://code.jquery.com/jquery-3.2.1.js", "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js", "https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js", "https://unpkg.com/react@15.3.2/dist/react.js", "http://builds.emberjs.com/tags/v2.11.0/ember.prod.js", "https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js", "https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js", ]; var results = {}; var remaining = 2 * urls.length; function done() { if (!--remaining) { var failures = []; urls.forEach(function(url) { var info = results[url]; console.log(); console.log(url); console.log(info.log); var elapsed = 0; info.log.replace(/: ([0-9]+\.[0-9]{3})s/g, function(match, time) { elapsed += parseFloat(time); }); console.log("Run-time:", elapsed.toFixed(3), "s"); console.log("Original:", info.input, "bytes"); console.log("Uglified:", info.output, "bytes"); console.log("SHA1 sum:", info.sha1); if (info.code) { failures.push(url); } }); if (failures.length) { console.error("Benchmark failed:"); failures.forEach(function(url) { console.error(url); }); process.exit(1); } } } urls.forEach(function(url) { results[url] = { input: 0, output: 0, log: "" }; require(url.slice(0, url.indexOf(":"))).get(url, function(res) { var uglifyjs = fork("bin/uglifyjs", args, { silent: true }); res.on("data", function(data) { results[url].input += data.length; }).pipe(uglifyjs.stdin); uglifyjs.stdout.on("data", function(data) { results[url].output += data.length; }).pipe(createHash("sha1")).on("data", function(data) { results[url].sha1 = data.toString("hex"); done(); }); uglifyjs.stderr.setEncoding("utf8"); uglifyjs.stderr.on("data", function(data) { results[url].log += data; }); uglifyjs.on("exit", function(code) { results[url].code = code; done(); }); }); }); UglifyJS2-2.8.29/test/compress/000077500000000000000000000000001312030606600162015ustar00rootroot00000000000000UglifyJS2-2.8.29/test/compress/angular-inject.js000066400000000000000000000027421312030606600214470ustar00rootroot00000000000000ng_inject_defun: { options = { angular: true }; input: { /*@ngInject*/ function Controller(dependency) { return dependency; } } expect: { function Controller(dependency) { return dependency; } Controller.$inject=['dependency'] } } ng_inject_assignment: { options = { angular: true }; input: { /*@ngInject*/ var Controller = function(dependency) { return dependency; } } expect: { var Controller = function(dependency) { return dependency; } Controller.$inject=['dependency'] } } ng_inject_inline: { options = { angular: true }; input: { angular.module('a'). factory('b', /*@ngInject*/ function(dependency) { return dependency; }). directive('c', /*@ngInject*/ function(anotherDependency) { return anotherDependency; }) } expect: { angular.module('a'). factory('b',[ 'dependency', function(dependency) { return dependency; }]). directive('c',[ 'anotherDependency', function(anotherDependency) { return anotherDependency; }]) } } UglifyJS2-2.8.29/test/compress/arrays.js000066400000000000000000000126761312030606600200540ustar00rootroot00000000000000holes_and_undefined: { input: { w = [1,,]; x = [1, 2, undefined]; y = [1, , 2, ]; z = [1, undefined, 3]; } expect: { w=[1,,]; x=[1,2,void 0]; y=[1,,2]; z=[1,void 0,3]; } } constant_join: { options = { unsafe : true, evaluate : true }; input: { var a = [ "foo", "bar", "baz" ].join(""); var a1 = [ "foo", "bar", "baz" ].join(); var a2 = [ "foo", "bar", "baz" ].join(null); var a3 = [ "foo", "bar", "baz" ].join(void 0); var a4 = [ "foo", , "baz" ].join(); var a5 = [ "foo", null, "baz" ].join(); var a6 = [ "foo", void 0, "baz" ].join(); var b = [ "foo", 1, 2, 3, "bar" ].join(""); var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join(""); var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join(""); var c2 = [ 1, 2, "foo", "bar", baz() ].join(""); var c3 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(""); var c4 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join(""); var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(); var c6 = [ 1, 2, null, undefined, "foo", "bar", baz() ].join(); var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-"); var e = [].join(foo + bar); var f = [].join(""); var g = [].join("foo"); } expect: { var a = "foobarbaz"; var a1 = "foo,bar,baz"; var a2 = "foonullbarnullbaz"; var a3 = "foo,bar,baz"; var a4 = "foo,,baz"; var a5 = "foo,,baz"; var a6 = "foo,,baz"; var b = "foo123bar"; var c = boo() + "foo123bar" + bar(); var c1 = "" + boo() + bar() + "foo123bar" + bar(); var c2 = "12foobar" + baz(); var c3 = boo() + bar() + "foo123bar" + bar() + "foo"; var c4 = "12foobar" + baz(); var c5 = [ boo() + bar() + "foo", 1, 2, 3, "bar", bar() + "foo" ].join(); var c6 = [ "1,2,,,foo,bar", baz() ].join(); var d = "foo-3bar-baz"; var e = [].join(foo + bar); var f = ""; var g = ""; } } constant_join_2: { options = { unsafe : true, evaluate : true }; input: { var a = [ "foo", "bar", boo(), "baz", "x", "y" ].join(""); var b = [ "foo", "bar", boo(), "baz", "x", "y" ].join("-"); var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator"); var d = [ "foo", "bar", boo(), [ "foo", 1, 2, 3, "bar" ].join("+"), "baz", "x", "y" ].join("-"); var e = [ "foo", "bar", boo(), [ "foo", 1, 2, 3, "bar" ].join("+"), "baz", "x", "y" ].join("really-long-separator"); var f = [ "str", "str" + variable, "foo", "bar", "moo" + foo ].join(""); } expect: { var a = "foobar" + boo() + "bazxy"; var b = [ "foo-bar", boo(), "baz-x-y" ].join("-"); var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator"); var d = [ "foo-bar", boo(), "foo+1+2+3+bar-baz-x-y" ].join("-"); var e = [ "foo", "bar", boo(), "foo+1+2+3+bar", "baz", "x", "y" ].join("really-long-separator"); var f = "strstr" + variable + "foobarmoo" + foo; } } constant_join_3: { options = { unsafe: true, evaluate: true, }; input: { var a = [ null ].join(); var b = [ , ].join(); var c = [ , 1, , 3 ].join(); var d = [ foo ].join(); var e = [ foo, null, undefined, bar ].join("-"); var f = [ foo, bar ].join(""); var g = [ null, "foo", null, bar + "baz" ].join(""); var h = [ null, "foo", null, bar + "baz" ].join("-"); var i = [ "foo" + bar, null, baz + "moo" ].join(""); var j = [ foo + "bar", baz ].join(""); var k = [ foo, "bar" + baz ].join(""); var l = [ foo, bar + "baz" ].join(""); } expect: { var a = ""; var b = ""; var c = ",1,,3"; var d = "" + foo; var e = [ foo, "-", bar ].join("-"); var f = "" + foo + bar; var g = "foo" + bar + "baz"; var h = [ "-foo-", bar + "baz" ].join("-"); var i = "foo" + bar + baz + "moo"; var j = foo + "bar" + baz; var k = foo + "bar" + baz; var l = foo + (bar + "baz"); } } for_loop: { options = { unsafe : true, unused : true, evaluate : true, reduce_vars : true }; input: { function f0() { var a = [1, 2, 3]; for (var i = 0; i < a.length; i++) { console.log(a[i]); } } function f1() { var a = [1, 2, 3]; for (var i = 0, len = a.length; i < len; i++) { console.log(a[i]); } } function f2() { var a = [1, 2, 3]; for (var i = 0; i < a.length; i++) { a[i]++; } } } expect: { function f0() { var a = [1, 2, 3]; for (var i = 0; i < 3; i++) console.log(a[i]); } function f1() { var a = [1, 2, 3]; for (var i = 0; i < 3; i++) console.log(a[i]); } function f2() { var a = [1, 2, 3]; for (var i = 0; i < a.length; i++) a[i]++; } } } UglifyJS2-2.8.29/test/compress/ascii.js000066400000000000000000000030141312030606600176250ustar00rootroot00000000000000ascii_only_true: { options = {} beautify = { ascii_only : true, screw_ie8 : true, beautify : false, } input: { function f() { return "\x000\x001\x007\x008\x00" + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; } } expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}' } ascii_only_false: { options = {} beautify = { ascii_only : false, screw_ie8 : true, beautify : false, } input: { function f() { return "\x000\x001\x007\x008\x00" + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; } } expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}' } UglifyJS2-2.8.29/test/compress/asm.js000066400000000000000000000074611312030606600173270ustar00rootroot00000000000000asm_mixed: { options = { sequences : true, properties : true, dead_code : true, drop_debugger : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, loops : true, unused : true, hoist_funs : true, keep_fargs : true, keep_fnames : false, hoist_vars : true, if_return : true, join_vars : true, cascade : true, side_effects : true, negate_iife : true }; input: { // adapted from http://asmjs.org/spec/latest/ function asm_GeometricMean(stdlib, foreign, buffer) { "use asm"; var exp = stdlib.Math.exp; var log = stdlib.Math.log; var values = new stdlib.Float64Array(buffer); function logSum(start, end) { start = start|0; end = end|0; var sum = 0.0, p = 0, q = 0; // asm.js forces byte addressing of the heap by requiring shifting by 3 for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) { sum = sum + +log(values[p>>3]); } return +sum; } function geometricMean(start, end) { start = start|0; end = end|0; return +exp(+logSum(start, end) / +((end - start)|0)); } return { geometricMean: geometricMean }; } function no_asm_GeometricMean(stdlib, foreign, buffer) { var exp = stdlib.Math.exp; var log = stdlib.Math.log; var values = new stdlib.Float64Array(buffer); function logSum(start, end) { start = start|0; end = end|0; var sum = 0.0, p = 0, q = 0; // asm.js forces byte addressing of the heap by requiring shifting by 3 for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) { sum = sum + +log(values[p>>3]); } return +sum; } function geometricMean(start, end) { start = start|0; end = end|0; return +exp(+logSum(start, end) / +((end - start)|0)); } return { geometricMean: geometricMean }; } } expect: { function asm_GeometricMean(stdlib, foreign, buffer) { "use asm"; var exp = stdlib.Math.exp; var log = stdlib.Math.log; var values = new stdlib.Float64Array(buffer); function logSum(start, end) { start = start | 0; end = end | 0; var sum = 0.0, p = 0, q = 0; for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) { sum = sum + +log(values[p >> 3]); } return +sum; } function geometricMean(start, end) { start = start | 0; end = end | 0; return +exp(+logSum(start, end) / +(end - start | 0)); } return { geometricMean: geometricMean }; } function no_asm_GeometricMean(stdlib, foreign, buffer) { function logSum(start, end) { start |= 0, end |= 0; var sum = 0, p = 0, q = 0; for (p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]); return +sum; } function geometricMean(start, end) { return start |= 0, end |= 0, +exp(+logSum(start, end) / +(end - start | 0)); } var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer); return { geometricMean: geometricMean }; } } } UglifyJS2-2.8.29/test/compress/assignment.js000066400000000000000000000103601312030606600207070ustar00rootroot00000000000000op_equals_left_local_var: { options = { evaluate: true, } input: { var x; x = x + 3; x = x - 3; x = x / 3; x = x * 3; x = x >> 3; x = x << 3; x = x >>> 3; x = x | 3; x = x ^ 3; x = x % 3; x = x & 3; x = x + g(); x = x - g(); x = x / g(); x = x * g(); x = x >> g(); x = x << g(); x = x >>> g(); x = x | g(); x = x ^ g(); x = x % g(); x = x & g(); } expect: { var x; x += 3; x -= 3; x /= 3; x *= 3; x >>= 3; x <<= 3; x >>>= 3; x |= 3; x ^= 3; x %= 3; x &= 3; x += g(); x -= g(); x /= g(); x *= g(); x >>= g(); x <<= g(); x >>>= g(); x |= g(); x ^= g(); x %= g(); x &= g(); } } op_equals_right_local_var: { options = { evaluate: true, } input: { var x; x = (x -= 2) ^ x; x = 3 + x; x = 3 - x; x = 3 / x; x = 3 * x; x = 3 >> x; x = 3 << x; x = 3 >>> x; x = 3 | x; x = 3 ^ x; x = 3 % x; x = 3 & x; x = g() + x; x = g() - x; x = g() / x; x = g() * x; x = g() >> x; x = g() << x; x = g() >>> x; x = g() | x; x = g() ^ x; x = g() % x; x = g() & x; } expect: { var x; x = (x -= 2) ^ x; x = 3 + x; x = 3 - x; x = 3 / x; x *= 3; x = 3 >> x; x = 3 << x; x = 3 >>> x; x |= 3; x ^= 3; x = 3 % x; x &= 3; x = g() + x; x = g() - x; x = g() / x; x = g() * x; x = g() >> x; x = g() << x; x = g() >>> x; x = g() | x; x = g() ^ x; x = g() % x; x = g() & x; } } op_equals_left_global_var: { options = { evaluate: true, } input: { x = x + 3; x = x - 3; x = x / 3; x = x * 3; x = x >> 3; x = x << 3; x = x >>> 3; x = x | 3; x = x ^ 3; x = x % 3; x = x & 3; x = x + g(); x = x - g(); x = x / g(); x = x * g(); x = x >> g(); x = x << g(); x = x >>> g(); x = x | g(); x = x ^ g(); x = x % g(); x = x & g(); } expect: { x += 3; x -= 3; x /= 3; x *= 3; x >>= 3; x <<= 3; x >>>= 3; x |= 3; x ^= 3; x %= 3; x &= 3; x += g(); x -= g(); x /= g(); x *= g(); x >>= g(); x <<= g(); x >>>= g(); x |= g(); x ^= g(); x %= g(); x &= g(); } } op_equals_right_global_var: { options = { evaluate: true, } input: { x = (x -= 2) ^ x; x = 3 + x; x = 3 - x; x = 3 / x; x = 3 * x; x = 3 >> x; x = 3 << x; x = 3 >>> x; x = 3 | x; x = 3 ^ x; x = 3 % x; x = 3 & x; x = g() + x; x = g() - x; x = g() / x; x = g() * x; x = g() >> x; x = g() << x; x = g() >>> x; x = g() | x; x = g() ^ x; x = g() % x; x = g() & x; } expect: { x = (x -= 2) ^ x; x = 3 + x; x = 3 - x; x = 3 / x; x *= 3; x = 3 >> x; x = 3 << x; x = 3 >>> x; x |= 3; x ^= 3; x = 3 % x; x &= 3; x = g() + x; x = g() - x; x = g() / x; x = g() * x; x = g() >> x; x = g() << x; x = g() >>> x; x = g() | x; x = g() ^ x; x = g() % x; x = g() & x; } } UglifyJS2-2.8.29/test/compress/blocks.js000066400000000000000000000014021312030606600200110ustar00rootroot00000000000000remove_blocks: { input: { {;} foo(); {}; { {}; }; bar(); {} } expect: { foo(); bar(); } } keep_some_blocks: { input: { // 1. if (foo) { {{{}}} if (bar) { baz(); } {{}} } else { stuff(); } // 2. if (foo) { for (var i = 0; i < 5; ++i) if (bar) baz(); } else { stuff(); } } expect: { // 1. if (foo) { if (bar) baz(); } else stuff(); // 2. if (foo) { for (var i = 0; i < 5; ++i) if (bar) baz(); } else stuff(); } } UglifyJS2-2.8.29/test/compress/collapse_vars.js000066400000000000000000001434341312030606600214050ustar00rootroot00000000000000collapse_vars_side_effects_1: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { var e = 7; var s = "abcdef"; var i = 2; var log = console.log.bind(console); var x = s.charAt(i++); var y = s.charAt(i++); var z = s.charAt(i++); log(x, y, z, e); } function f2() { var e = 7; var log = console.log.bind(console); var s = "abcdef"; var i = 2; var x = s.charAt(i++); var y = s.charAt(i++); var z = s.charAt(i++); log(x, i, y, z, e); } function f3() { var e = 7; var s = "abcdef"; var i = 2; var log = console.log.bind(console); var x = s.charAt(i++); var y = s.charAt(i++); var z = s.charAt(i++); log(x, z, y, e); } function f4() { var log = console.log.bind(console), i = 10, x = i += 2, y = i += 3, z = i += 4; log(x, z, y, i); } f1(), f2(), f3(), f4(); } expect: { function f1() { var s = "abcdef", i = 2; console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(i++), 7); } function f2() { var log = console.log.bind(console), s = "abcdef", i = 2, x = s.charAt(i++), y = s.charAt(i++), z = s.charAt(i++); log(x, i, y, z, 7); } function f3() { var s = "abcdef", i = 2, log = console.log.bind(console), x = s.charAt(i++), y = s.charAt(i++); log(x, s.charAt(i++), y, 7); } function f4() { var log = console.log.bind(console), i = 10, x = i += 2, y = i += 3; log(x, i += 4, y, i); } f1(), f2(), f3(), f4(); } expect_stdout: true } collapse_vars_side_effects_2: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function fn(x) { return console.log(x), x; } function p1() { var a = foo(), b = bar(), c = baz(); return a + b + c; } function p2() { var a = foo(), c = bar(), b = baz(); return a + b + c; } function p3() { var b = foo(), a = bar(), c = baz(); return a + b + c; } function p4() { var b = foo(), c = bar(), a = baz(); return a + b + c; } function p5() { var c = foo(), a = bar(), b = baz(); return a + b + c; } function p6() { var c = foo(), b = bar(), a = baz(); return a + b + c; } function q1() { var a = foo(), b = bar(), c = baz(); return fn(a + b + c); } function q2() { var a = foo(), c = bar(), b = baz(); return fn(a + b + c); } function q3() { var b = foo(), a = bar(), c = baz(); return fn(a + b + c); } function q4() { var b = foo(), c = bar(), a = baz(); return fn(a + b + c); } function q5() { var c = foo(), a = bar(), b = baz(); return fn(a + b + c); } function q6() { var c = foo(), b = bar(), a = baz(); return fn(a + b + c); } function r1() { var a = foo(), b = bar(), c = baz(); return fn(a) + fn(b) + fn(c); } function r2() { var a = foo(), c = bar(), b = baz(); return fn(a) + fn(b) + fn(c); } function r3() { var b = foo(), a = bar(), c = baz(); return fn(a) + fn(b) + fn(c); } function r4() { var b = foo(), c = bar(), a = baz(); return fn(a) + fn(b) + fn(c); } function r5() { var c = foo(), a = bar(), b = baz(); return fn(a) + fn(b) + fn(c); } function r6() { var c = foo(), b = bar(), a = baz(); return fn(a) + fn(b) + fn(c); } function s1() { var a = foo(), b = bar(), c = baz(); return g(a + b + c); } function s6() { var c = foo(), b = bar(), a = baz(); return g(a + b + c); } function t1() { var a = foo(), b = bar(), c = baz(); return g(a) + g(b) + g(c); } function t6() { var c = foo(), b = bar(), a = baz(); return g(a) + g(b) + g(c); } } expect: { function fn(x) { return console.log(x), x; } function p1() { return foo() + bar() + baz(); } function p2() { var a = foo(), c = bar(); return a + baz() + c; } function p3() { var b = foo(); return bar() + b + baz(); } function p4() { var b = foo(), c = bar(); return baz() + b + c; } function p5() { var c = foo(); return bar() + baz() + c; } function p6() { var c = foo(), b = bar(); return baz() + b + c; } function q1() { return fn(foo() + bar() + baz()); } function q2() { var a = foo(), c = bar(); return fn(a + baz() + c); } function q3() { var b = foo(); return fn(bar() + b + baz()); } function q4() { var b = foo(), c = bar(); return fn(baz() + b + c); } function q5() { var c = foo(); return fn(bar() + baz() + c); } function q6() { var c = foo(), b = bar(); return fn(baz() + b + c); } function r1() { var a = foo(), b = bar(), c = baz(); return fn(a) + fn(b) + fn(c); } function r2() { var a = foo(), c = bar(), b = baz(); return fn(a) + fn(b) + fn(c); } function r3() { var b = foo(), a = bar(), c = baz(); return fn(a) + fn(b) + fn(c); } function r4() { var b = foo(), c = bar(); return fn(baz()) + fn(b) + fn(c); } function r5() { var c = foo(), a = bar(), b = baz(); return fn(a) + fn(b) + fn(c); } function r6() { var c = foo(), b = bar(); return fn(baz()) + fn(b) + fn(c); } function s1() { var a = foo(), b = bar(), c = baz(); return g(a + b + c); } function s6() { var c = foo(), b = bar(), a = baz(); return g(a + b + c); } function t1() { var a = foo(), b = bar(), c = baz(); return g(a) + g(b) + g(c); } function t6() { var c = foo(), b = bar(), a = baz(); return g(a) + g(b) + g(c); } } } collapse_vars_issue_721: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { define(["require", "exports", 'handlebars'], function (require, exports, hb) { var win = window; var _hb = win.Handlebars = hb; return _hb; }); def(function (hb) { var win = window; var prop = 'Handlebars'; var _hb = win[prop] = hb; return _hb; }); def(function (hb) { var prop = 'Handlebars'; var win = window; var _hb = win[prop] = hb; return _hb; }); def(function (hb) { var prop = 'Handlebars'; var win = g(); var _hb = win[prop] = hb; return _hb; }); def(function (hb) { var prop = g1(); var win = g2(); var _hb = win[prop] = hb; return _hb; }); def(function (hb) { var win = g2(); var prop = g1(); var _hb = win[prop] = hb; return _hb; }); } expect: { define([ "require", "exports", "handlebars" ], function(require, exports, hb) { return window.Handlebars = hb; }), def(function(hb) { return window.Handlebars = hb; }), def(function(hb) { return window.Handlebars = hb; }), def(function (hb) { return g().Handlebars = hb; }), def(function (hb) { var prop = g1(); return g2()[prop] = hb; }), def(function (hb) { return g2()[g1()] = hb; }); } } collapse_vars_properties: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1(obj) { var prop = 'LiteralProperty'; return !!-+obj[prop]; } function f2(obj) { var prop1 = 'One'; var prop2 = 'Two'; return ~!!-+obj[prop1 + prop2]; } } expect: { function f1(obj) { return !!-+obj.LiteralProperty; } function f2(obj) { return ~!!-+obj.OneTwo; } } } collapse_vars_if: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { var not_used = sideeffect(), x = g1 + g2; var y = x / 4, z = 'Bar' + y; if ('x' != z) { return g9; } else return g5; } function f2() { var x = g1 + g2, not_used = sideeffect(); var y = x / 4 var z = 'Bar' + y; if ('x' != z) { return g9; } else return g5; } function f3(x) { if (x) { var a = 1; return a; } else { var b = 2; return b; } } } expect: { function f1() { sideeffect(); return "x" != "Bar" + (g1 + g2) / 4 ? g9 : g5; } function f2() { var x = g1 + g2; sideeffect(); return "x" != "Bar" + x / 4 ? g9 : g5; } function f3(x) { if (x) { return 1; } return 2; } } } collapse_vars_while: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1(y) { // Neither the non-constant while condition `c` will be // replaced, nor the non-constant `x` in the body. var x = y, c = 3 - y; while (c) { return x; } var z = y * y; return z; } function f2(y) { // The constant `x` will be replaced in the while body. var x = 7; while (y) { return x; } var z = y * y; return z; } function f3(y) { // The non-constant `n` will not be replaced in the while body. var n = 5 - y; while (y) { return n; } var z = y * y; return z; } } expect: { function f1(y) { var x = y, c = 3 - y; while (c) return x; return y * y; } function f2(y) { while (y) return 7; return y * y } function f3(y) { var n = 5 - y; while (y) return n; return y * y; } } } collapse_vars_do_while: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:false, loops:false, unused:"keep_assign", hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1(y) { // The constant do-while condition `c` will not be replaced. var c = 9; do {} while (c === 77); } function f2(y) { // The non-constant do-while condition `c` will not be replaced. var c = 5 - y; do { } while (c); } function f3(y) { // The constant `x` will be replaced in the do loop body. function fn(n) { console.log(n); } var a = 2, x = 7; do { fn(a = x); break; } while (y); } function f4(y) { // The non-constant `a` will not be replaced in the do loop body. var a = y / 4; do { return a; } while (y); } function f5(y) { function p(x) { console.log(x); } do { // The non-constant `a` will be replaced in p(a) // because it is declared in same block. var a = y - 3; p(a); } while (--y); } } expect: { function f1(y) { var c = 9; do ; while (77 === c); } function f2(y) { var c = 5 - y; do ; while (c); } function f3(y) { function fn(n) { console.log(n); } var a = 2; do { fn(a = 7); break; } while (y); } function f4(y) { var a = y / 4; do return a; while (y); } function f5(y) { function p(x) { console.log(x); } do { p(y - 3); } while (--y); } } } collapse_vars_do_while_drop_assign: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:false, loops:false, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1(y) { // The constant do-while condition `c` will be not replaced. var c = 9; do {} while (c === 77); } function f2(y) { // The non-constant do-while condition `c` will not be replaced. var c = 5 - y; do { } while (c); } function f3(y) { // The constant `x` will be replaced in the do loop body. function fn(n) { console.log(n); } var a = 2, x = 7; do { fn(a = x); break; } while (y); } function f4(y) { // The non-constant `a` will not be replaced in the do loop body. var a = y / 4; do { return a; } while (y); } function f5(y) { function p(x) { console.log(x); } do { // The non-constant `a` will be replaced in p(a) // because it is declared in same block. var a = y - 3; p(a); } while (--y); } } expect: { function f1(y) { var c = 9; do ; while (77 === c); } function f2(y) { var c = 5 - y; do ; while (c); } function f3(y) { function fn(n) { console.log(n); } do { fn(7); break; } while (y); } function f4(y) { var a = y / 4; do return a; while (y); } function f5(y) { function p(x) { console.log(x); } do { p(y - 3); } while (--y); } } } collapse_vars_seq: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { var f1 = function(x, y) { var a, b, r = x + y, q = r * r, z = q - r; a = z, b = 7; return a + b; }; } expect: { var f1 = function(x, y) { var a, b, r = x + y; return a = r * r - r, b = 7, a + b }; } } collapse_vars_throw: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { var f1 = function(x, y) { var a, b, r = x + y, q = r * r, z = q - r; a = z, b = 7; throw a + b; }; } expect: { var f1 = function(x, y) { var a, b, r = x + y; throw a = r * r - r, b = 7, a + b }; } } collapse_vars_switch: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { var not_used = sideeffect(), x = g1 + g2; var y = x / 4, z = 'Bar' + y; switch (z) { case 0: return g9; } } function f2() { var x = g1 + g2, not_used = sideeffect(); var y = x / 4 var z = 'Bar' + y; switch (z) { case 0: return g9; } } function f3(x) { switch(x) { case 1: var a = 3 - x; return a; } } } expect: { function f1() { sideeffect(); switch ("Bar" + (g1 + g2) / 4) { case 0: return g9 } } function f2() { var x = g1 + g2; sideeffect(); switch ("Bar" + x / 4) { case 0: return g9 } } function f3(x) { // verify no extraneous semicolon in case block before return // when the var definition was eliminated switch(x) { case 1: return 3 - x; } } } } collapse_vars_assignment: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function log(x) { return console.log(x), x; } function f0(c) { var a = 3 / c; return a = a; } function f1(c) { const a = 3 / c; const b = 1 - a; return b; } function f2(c) { var a = 3 / c; var b = a - 7; return log(c = b); } function f3(c) { var a = 3 / c; var b = a - 7; return log(c |= b); } function f4(c) { var a = 3 / c; var b = 2; return log(b += a); } function f5(c) { var b = 2; var a = 3 / c; return log(b += a); } function f6(c) { var b = g(); var a = 3 / c; return log(b += a); } } expect: { function log(x) { return console.log(x), x; } function f0(c) { var a = 3 / c; return a = a; } function f1(c) { return 1 - 3 / c } function f2(c) { return log(c = 3 / c - 7); } function f3(c) { return log(c |= 3 / c - 7); } function f4(c) { var b = 2; return log(b += 3 / c); } function f5(c) { var b = 2; return log(b += 3 / c); } function f6(c) { var b = g(); return log(b += 3 / c); } } } collapse_vars_lvalues: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:"keep_assign", hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f0(x) { var i = ++x; return x += i; } function f1(x) { var a = (x -= 3); return x += a; } function f2(x) { var z = x, a = ++z; return z += a; } function f3(x) { var a = (x -= 3), b = x + a; return b; } function f4(x) { var a = (x -= 3); return x + a; } function f5(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return b - c; } function f6(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return c - b; } function f7(x) { var w = e1(), v = e2(), c = v - x, b = w = x; return b - c; } function f8(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return b - c; } function f9(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return c - b; } } expect: { function f0(x) { var i = ++x; return x += i; } function f1(x) { var a = (x -= 3); return x += a; } function f2(x) { var z = x, a = ++z; return z += a; } function f3(x) { var a = (x -= 3); return x + a; } function f4(x) { var a = (x -= 3); return x + a; } function f5(x) { var w = e1(), v = e2(), c = v = --x; return (w = x) - c; } function f6(x) { var w = e1(), v = e2(); return (v = --x) - (w = x); } function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; } function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); } function f9(x) { var w = e1(); return e2() - x - (w = x); } } } collapse_vars_lvalues_drop_assign: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f0(x) { var i = ++x; return x += i; } function f1(x) { var a = (x -= 3); return x += a; } function f2(x) { var z = x, a = ++z; return z += a; } function f3(x) { var a = (x -= 3), b = x + a; return b; } function f4(x) { var a = (x -= 3); return x + a; } function f5(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return b - c; } function f6(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return c - b; } function f7(x) { var w = e1(), v = e2(), c = v - x, b = w = x; return b - c; } function f8(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return b - c; } function f9(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return c - b; } } expect: { function f0(x) { var i = ++x; return x += i; } function f1(x) { var a = (x -= 3); return x += a; } function f2(x) { var z = x, a = ++z; return z += a; } function f3(x) { var a = (x -= 3); return x + a; } function f4(x) { var a = (x -= 3); return x + a; } function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; } function f6(x) { e1(), e2(); return --x - x; } function f7(x) { var v = (e1(), e2()), c = v - x; return x - c; } function f8(x) { var v = (e1(), e2()); return x - (v - x); } function f9(x) { e1(); return e2() - x - x; } } } collapse_vars_misc1: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f0(o, a, h) { var b = 3 - a; var obj = o; var seven = 7; var prop = 'run'; var t = obj[prop](b)[seven] = h; return t; } function f1(x) { var y = 5 - x; return y; } function f2(x) { const z = foo(), y = z / (5 - x); return y; } function f3(x) { var z = foo(), y = (5 - x) / z; return y; } function f4(x) { var z = foo(), y = (5 - u) / z; return y; } function f5(x) { const z = foo(), y = (5 - window.x) / z; return y; } function f6() { var b = window.a * window.z; return b && zap(); } function f7() { var b = window.a * window.z; return b + b; } function f8() { var b = window.a * window.z; var c = b + 5; return b + c; } function f9() { var b = window.a * window.z; return bar() || b; } function f10(x) { var a = 5, b = 3; return a += b; } function f11(x) { var a = 5, b = 3; return a += --b; } } expect: { function f0(o, a, h) { var b = 3 - a; return o.run(b)[7] = h; } function f1(x) { return 5 - x } function f2(x) { return foo() / (5 - x) } function f3(x) { return (5 - x) / foo() } function f4(x) { var z = foo(); return (5 - u) / z } function f5(x) { const z = foo(); return (5 - window.x) / z } function f6() { return window.a * window.z && zap() } function f7() { var b = window.a * window.z; return b + b } function f8() { var b = window.a * window.z; return b + (b + 5) } function f9() { var b = window.a * window.z; return bar() || b } function f10(x) { var a = 5; return a += 3; } function f11(x) { var a = 5, b = 3; return a += --b; } } } collapse_vars_self_reference: { options = { collapse_vars:true, unused:false, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { // avoid bug in self-referential declaration. function f1() { var self = { inner: function() { return self; } }; } function f2() { var self = { inner: self }; } } expect: { // note: `unused` option is false function f1() { var self = { inner: function() { return self } }; } function f2() { var self = { inner: self }; } } } collapse_vars_repeated: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { var dummy = 3, a = 5, unused = 2, a = 1, a = 3; return -a; } function f2(x) { var a = 3, a = x; return a; } (function(x){ var a = "GOOD" + x, e = "BAD", k = "!", e = a; console.log(e + k); })("!"), (function(x){ var a = "GOOD" + x, e = "BAD" + x, k = "!", e = a; console.log(e + k); })("!"); } expect: { function f1() { return -3 } function f2(x) { return x } (function(x){ var a = "GOOD" + x, e = "BAD", e = a; console.log(e + "!"); })("!"), (function(x){ var a = "GOOD" + x, e = "BAD" + x, e = a; console.log(e + "!"); })("!"); } expect_stdout: true } collapse_vars_closures: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function constant_vars_can_be_replaced_in_any_scope() { var outer = 3; return function() { return outer; } } function non_constant_vars_can_only_be_replace_in_same_scope(x) { var outer = x; return function() { return outer; } } } expect: { function constant_vars_can_be_replaced_in_any_scope() { return function() { return 3 } } function non_constant_vars_can_only_be_replace_in_same_scope(x) { var outer = x return function() { return outer } } } } collapse_vars_unary: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f0(o, p) { var x = o[p]; delete x; } function f1(n) { var k = !!n; return n > +k; } function f2(n) { // test unary with constant var k = 7; return k--; } function f3(n) { // test unary with constant var k = 7; return ++k; } function f4(n) { // test unary with non-constant var k = 8 - n; return k--; } function f5(n) { // test unary with non-constant var k = 9 - n; return ++k; } } expect: { function f0(o, p) { var x = o[p]; delete x; } function f1(n) { return n > +!!n } function f2(n) { var k = 7; return k-- } function f3(n) { var k = 7; return ++k } function f4(n) { var k = 8 - n; return k--; } function f5(n) { var k = 9 - n; return ++k; } } } collapse_vars_try: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { try { var a = 1; return a; } catch (ex) { var b = 2; return b; } finally { var c = 3; return c; } } function f2() { var t = could_throw(); // shouldn't be replaced in try block try { return t + might_throw(); } catch (ex) { return 3; } } } expect: { function f1() { try { return 1; } catch (ex) { return 2; } finally { return 3; } } function f2() { var t = could_throw(); try { return t + might_throw(); } catch (ex) { return 3; } } } } collapse_vars_array: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1(x, y) { var z = x + y; return [z]; } function f2(x, y) { var z = x + y; return [x, side_effect(), z]; } function f3(x, y) { var z = f(x + y); return [ [3], [z, x, y], [g()] ]; } } expect: { function f1(x, y) { return [x + y] } function f2(x, y) { var z = x + y return [x, side_effect(), z] } function f3(x, y) { return [ [3], [f(x + y), x, y], [g()] ] } } } collapse_vars_object: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f0(x, y) { var z = x + y; return { get b() { return 7; }, r: z }; } function f1(x, y) { var z = x + y; return { r: z, get b() { return 7; } }; } function f2(x, y) { var z = x + y; var k = x - y; return { q: k, r: g(x), s: z }; } function f3(x, y) { var z = f(x + y); return [{ a: {q: x, r: y, s: z}, b: g() }]; } } expect: { function f0(x, y) { var z = x + y; return { get b() { return 7; }, r: z }; } function f1(x, y) { return { r: x + y, get b() { return 7; } }; } function f2(x, y) { var z = x + y; return { q: x - y, r: g(x), s: z }; } function f3(x, y) { return [{ a: {q: x, r: y, s: f(x + y)}, b: g() }]; } } } collapse_vars_eval_and_with: { options = { collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { // Don't attempt to collapse vars in presence of eval() or with statement. (function f0() { var a = 2; console.log(a - 5); eval("console.log(a);"); })(); (function f1() { var o = {a: 1}, a = 2; with (o) console.log(a); })(); (function f2() { var o = {a: 1}, a = 2; return function() { with (o) console.log(a) }; })()(); } expect: { (function f0() { var a = 2; console.log(a - 5); eval("console.log(a);"); })(); (function f1() { var o = {a: 1}, a = 2; with(o) console.log(a); })(); (function f2() { var o = {a: 1}, a = 2; return function() { with (o) console.log(a) }; })()(); } expect_stdout: true } collapse_vars_constants: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1(x) { var a = 4, b = x.prop, c = 5, d = sideeffect1(), e = sideeffect2(); return b + (function() { return d - a * e - c; })(); } function f2(x) { var a = 4, b = x.prop, c = 5, not_used = sideeffect1(), e = sideeffect2(); return b + (function() { return -a * e - c; })(); } function f3(x) { var a = 4, b = x.prop, c = 5, not_used = sideeffect1(); return b + (function() { return -a - c; })(); } } expect: { function f1(x) { var b = x.prop, d = sideeffect1(), e = sideeffect2(); return b + (function() { return d - 4 * e - 5; })(); } function f2(x) { var b = x.prop, e = (sideeffect1(), sideeffect2()); return b + (function() { return -4 * e - 5; })(); } function f3(x) { var b = x.prop; sideeffect1(); return b + -9; } } } collapse_vars_arguments: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, toplevel:true } input: { var outer = function() { // Do not replace `arguments` but do replace the constant `k` before it. var k = 7, arguments = 5, inner = function() { console.log(arguments); } inner(k, 1); } outer(); } expect: { (function() { (function(){console.log(arguments);})(7, 1); })(); } expect_stdout: true } collapse_vars_short_circuit: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f0(x) { var a = foo(), b = bar(); return b || x; } function f1(x) { var a = foo(), b = bar(); return b && x; } function f2(x) { var a = foo(), b = bar(); return x && a && b; } function f3(x) { var a = foo(), b = bar(); return a && x; } function f4(x) { var a = foo(), b = bar(); return a && x && b; } function f5(x) { var a = foo(), b = bar(); return x || a || b; } function f6(x) { var a = foo(), b = bar(); return a || x || b; } function f7(x) { var a = foo(), b = bar(); return a && b && x; } function f8(x,y) { var a = foo(), b = bar(); return (x || a) && (y || b); } function f9(x,y) { var a = foo(), b = bar(); return (x && a) || (y && b); } function f10(x,y) { var a = foo(), b = bar(); return (x - a) || (y - b); } function f11(x,y) { var a = foo(), b = bar(); return (x - b) || (y - a); } function f12(x,y) { var a = foo(), b = bar(); return (x - y) || (b - a); } function f13(x,y) { var a = foo(), b = bar(); return (a - b) || (x - y); } function f14(x,y) { var a = foo(), b = bar(); return (b - a) || (x - y); } } expect: { function f0(x) { foo(); return bar() || x; } function f1(x) { foo(); return bar() && x; } function f2(x) { var a = foo(), b = bar(); return x && a && b; } function f3(x) { var a = foo(); bar(); return a && x; } function f4(x) { var a = foo(), b = bar(); return a && x && b; } function f5(x) { var a = foo(), b = bar(); return x || a || b; } function f6(x) { var a = foo(), b = bar(); return a || x || b; } function f7(x) { var a = foo(), b = bar(); return a && b && x; } function f8(x,y) { var a = foo(), b = bar(); return (x || a) && (y || b); } function f9(x,y) { var a = foo(), b = bar(); return (x && a) || (y && b); } function f10(x,y) { var a = foo(), b = bar(); return (x - a) || (y - b); } function f11(x,y) { var a = foo(); return (x - bar()) || (y - a); } function f12(x,y) { var a = foo(), b = bar(); return (x - y) || (b - a); } function f13(x,y) { return (foo() - bar()) || (x - y); } function f14(x,y) { var a = foo(); return (bar() - a) || (x - y); } } } collapse_vars_short_circuited_conditions: { options = { collapse_vars: true, sequences: false, dead_code: true, conditionals: false, comparisons: false, evaluate: true, booleans: true, loops: true, unused: true, hoist_funs: true, keep_fargs: true, if_return: false, join_vars: true, cascade: true, side_effects: true, } input: { function c1(x) { var a = foo(), b = bar(), c = baz(); return a ? b : c; } function c2(x) { var a = foo(), b = bar(), c = baz(); return a ? c : b; } function c3(x) { var a = foo(), b = bar(), c = baz(); return b ? a : c; } function c4(x) { var a = foo(), b = bar(), c = baz(); return b ? c : a; } function c5(x) { var a = foo(), b = bar(), c = baz(); return c ? a : b; } function c6(x) { var a = foo(), b = bar(), c = baz(); return c ? b : a; } function i1(x) { var a = foo(), b = bar(), c = baz(); if (a) return b; else return c; } function i2(x) { var a = foo(), b = bar(), c = baz(); if (a) return c; else return b; } function i3(x) { var a = foo(), b = bar(), c = baz(); if (b) return a; else return c; } function i4(x) { var a = foo(), b = bar(), c = baz(); if (b) return c; else return a; } function i5(x) { var a = foo(), b = bar(), c = baz(); if (c) return a; else return b; } function i6(x) { var a = foo(), b = bar(), c = baz(); if (c) return b; else return a; } } expect: { function c1(x) { var a = foo(), b = bar(), c = baz(); return a ? b : c; } function c2(x) { var a = foo(), b = bar(), c = baz(); return a ? c : b; } function c3(x) { var a = foo(), b = bar(), c = baz(); return b ? a : c; } function c4(x) { var a = foo(), b = bar(), c = baz(); return b ? c : a; } function c5(x) { var a = foo(), b = bar(); return baz() ? a : b; } function c6(x) { var a = foo(), b = bar(); return baz() ? b : a; } function i1(x) { var a = foo(), b = bar(), c = baz(); if (a) return b; else return c; } function i2(x) { var a = foo(), b = bar(), c = baz(); if (a) return c; else return b; } function i3(x) { var a = foo(), b = bar(), c = baz(); if (b) return a; else return c; } function i4(x) { var a = foo(), b = bar(), c = baz(); if (b) return c; else return a; } function i5(x) { var a = foo(), b = bar(); if (baz()) return a; else return b; } function i6(x) { var a = foo(), b = bar(); if (baz()) return b; else return a; } } } collapse_vars_regexp: { options = { collapse_vars: true, loops: false, sequences: true, dead_code: true, conditionals: true, comparisons: true, evaluate: true, booleans: true, unused: true, hoist_funs: true, keep_fargs: true, if_return: true, join_vars: true, cascade: true, side_effects: true, } input: { function f1() { var k = 9; var rx = /[A-Z]+/; return [rx, k]; } function f2() { var rx = /[abc123]+/; return function(s) { return rx.exec(s); }; } (function(){ var result; var s = 'acdabcdeabbb'; var rx = /ab*/g; while (result = rx.exec(s)) { console.log(result[0]); } })(); } expect: { function f1() { return [/[A-Z]+/, 9]; } function f2() { var rx = /[abc123]+/; return function(s) { return rx.exec(s); }; } (function(){ var result, s = "acdabcdeabbb", rx = /ab*/g; while (result = rx.exec(s)) console.log(result[0]); })(); } expect_stdout: true } issue_1537: { options = { collapse_vars: true, } input: { var k = ''; for (k in {prop: 'val'}){} } expect: { var k = ''; for (k in {prop: 'val'}); } } issue_1562: { options = { collapse_vars: true, toplevel: true, } input: { var v = 1, B = 2; for (v in objs) f(B); var x = 3, C = 10; while(x + 2) bar(C); var y = 4, D = 20; do bar(D); while(y + 2); var z = 5, E = 30; for (; f(z + 2) ;) bar(E); } expect: { var v = 1; for (v in objs) f(2); var x = 3; while(x + 2) bar(10); var y = 4; do bar(20); while(y + 2); var z = 5; for (; f(z + 2) ;) bar(30); } } issue_1605_1: { options = { collapse_vars: true, toplevel: false, } input: { function foo(x) { var y = x; return y; } var o = new Object; o.p = 1; } expect: { function foo(x) { return x; } var o = new Object; o.p = 1; } } issue_1605_2: { options = { collapse_vars: true, toplevel: "vars", } input: { function foo(x) { var y = x; return y; } var o = new Object; o.p = 1; } expect: { function foo(x) { return x; } (new Object).p = 1; } } issue_1631_1: { options = { cascade: true, collapse_vars: true, hoist_funs: true, join_vars: true, sequences: true, side_effects: true, } input: { var pc = 0; function f(x) { pc = 200; return 100; } function x() { var t = f(); pc += t; return pc; } console.log(x()); } expect: { function f(x) { return pc = 200, 100; } function x() { var t = f(); return pc += t; } var pc = 0; console.log(x()); } expect_stdout: "300" } issue_1631_2: { options = { cascade: true, collapse_vars: true, hoist_funs: true, join_vars: true, sequences: true, side_effects: true, } input: { var a = 0, b = 1; function f() { a = 2; return 4; } function g() { var t = f(); b = a + t; return b; } console.log(g()); } expect: { function f() { return a = 2, 4; } function g() { var t = f(); return b = a + t; } var a = 0, b = 1; console.log(g()); } expect_stdout: "6" } issue_1631_3: { options = { cascade: true, collapse_vars: true, hoist_funs: true, join_vars: true, sequences: true, side_effects: true, } input: { function g() { var a = 0, b = 1; function f() { a = 2; return 4; } var t = f(); b = a + t; return b; } console.log(g()); } expect: { function g() { function f() { return a = 2, 4; } var a = 0, b = 1, t = f(); return b = a + t; } console.log(g()); } expect_stdout: "6" } var_side_effects_1: { options = { collapse_vars: true, } input: { var print = console.log.bind(console); function foo(x) { var twice = x * 2; print('Foo:', twice); } foo(10); } expect: { var print = console.log.bind(console); function foo(x) { print('Foo:', 2 * x); } foo(10); } expect_stdout: true } var_side_effects_2: { options = { collapse_vars: true, } input: { var print = console.log.bind(console); function foo(x) { var twice = x.y * 2; print('Foo:', twice); } foo({ y: 10 }); } expect: { var print = console.log.bind(console); function foo(x) { var twice = 2 * x.y; print('Foo:', twice); } foo({ y: 10 }); } expect_stdout: true } var_side_effects_3: { options = { collapse_vars: true, pure_getters: true, unsafe: true, } input: { var print = console.log.bind(console); function foo(x) { var twice = x.y * 2; print('Foo:', twice); } foo({ y: 10 }); } expect: { var print = console.log.bind(console); function foo(x) { print('Foo:', 2 * x.y); } foo({ y: 10 }); } expect_stdout: true } reassign_const_1: { options = { collapse_vars: true, } input: { function f() { const a = 1; a = 2; return a; } console.log(f()); } expect: { function f() { const a = 1; a = 2; return a; } console.log(f()); } expect_stdout: true } reassign_const_2: { options = { collapse_vars: true, } input: { function f() { const a = 1; ++a; return a; } console.log(f()); } expect: { function f() { const a = 1; ++a; return a; } console.log(f()); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/comparing.js000066400000000000000000000034171312030606600205230ustar00rootroot00000000000000keep_comparisons: { options = { comparisons: true, unsafe_comps: false } input: { var obj1 = { valueOf: function() {triggeredFirst();} } var obj2 = { valueOf: function() {triggeredSecond();} } var result1 = obj1 <= obj2; var result2 = obj1 < obj2; var result3 = obj1 >= obj2; var result4 = obj1 > obj2; } expect: { var obj1 = { valueOf: function() {triggeredFirst();} } var obj2 = { valueOf: function() {triggeredSecond();} } var result1 = obj1 <= obj2; var result2 = obj1 < obj2; var result3 = obj1 >= obj2; var result4 = obj1 > obj2; } } keep_comparisons_with_unsafe_comps: { options = { comparisons: true, unsafe_comps: true } input: { var obj1 = { valueOf: function() {triggeredFirst();} } var obj2 = { valueOf: function() {triggeredSecond();} } var result1 = obj1 <= obj2; var result2 = obj1 < obj2; var result3 = obj1 >= obj2; var result4 = obj1 > obj2; } expect: { var obj1 = { valueOf: function() {triggeredFirst();} } var obj2 = { valueOf: function() {triggeredSecond();} } var result1 = obj2 >= obj1; var result2 = obj2 > obj1; var result3 = obj1 >= obj2; var result4 = obj1 > obj2; } } dont_change_in_or_instanceof_expressions: { input: { 1 in 1; null in null; 1 instanceof 1; null instanceof null; } expect: { 1 in 1; null in null; 1 instanceof 1; null instanceof null; } }UglifyJS2-2.8.29/test/compress/concat-strings.js000066400000000000000000000123401312030606600214750ustar00rootroot00000000000000concat_1: { options = { evaluate: true }; input: { var a = "foo" + "bar" + x() + "moo" + "foo" + y() + "x" + "y" + "z" + q(); var b = "foo" + 1 + x() + 2 + "boo"; var c = 1 + x() + 2 + "boo"; // this CAN'T safely be shortened to 1 + x() + "5boo" var d = 1 + x() + 2 + 3 + "boo"; var e = 1 + x() + 2 + "X" + 3 + "boo"; // be careful with concatentation with "\0" with octal-looking strings. var f = "\0" + 360 + "\0" + 8 + "\0"; } expect: { var a = "foobar" + x() + "moofoo" + y() + "xyz" + q(); var b = "foo1" + x() + "2boo"; var c = 1 + x() + 2 + "boo"; var d = 1 + x() + 2 + 3 + "boo"; var e = 1 + x() + 2 + "X3boo"; var f = "\x00360\08\0"; } } concat_2: { options = {}; input: { console.log( 1 + (2 + 3), 1 + (2 + "3"), 1 + ("2" + 3), 1 + ("2" + "3"), "1" + (2 + 3), "1" + (2 + "3"), "1" + ("2" + 3), "1" + ("2" + "3") ); } expect: { console.log( 1 + (2 + 3), 1 + (2 + "3"), 1 + "2" + 3, 1 + "2" + "3", "1" + (2 + 3), "1" + 2 + "3", "1" + "2" + 3, "1" + "2" + "3" ); } expect_stdout: true } concat_3: { options = {}; input: { console.log( 1 + 2 + (3 + 4 + 5), 1 + 2 + (3 + 4 + "5"), 1 + 2 + (3 + "4" + 5), 1 + 2 + (3 + "4" + "5"), 1 + 2 + ("3" + 4 + 5), 1 + 2 + ("3" + 4 + "5"), 1 + 2 + ("3" + "4" + 5), 1 + 2 + ("3" + "4" + "5") ); } expect: { console.log( 1 + 2 + (3 + 4 + 5), 1 + 2 + (3 + 4 + "5"), 1 + 2 + (3 + "4") + 5, 1 + 2 + (3 + "4") + "5", 1 + 2 + "3" + 4 + 5, 1 + 2 + "3" + 4 + "5", 1 + 2 + "3" + "4" + 5, 1 + 2 + "3" + "4" + "5" ); } expect_stdout: true } concat_4: { options = {}; input: { console.log( 1 + "2" + (3 + 4 + 5), 1 + "2" + (3 + 4 + "5"), 1 + "2" + (3 + "4" + 5), 1 + "2" + (3 + "4" + "5"), 1 + "2" + ("3" + 4 + 5), 1 + "2" + ("3" + 4 + "5"), 1 + "2" + ("3" + "4" + 5), 1 + "2" + ("3" + "4" + "5") ); } expect: { console.log( 1 + "2" + (3 + 4 + 5), 1 + "2" + (3 + 4) + "5", 1 + "2" + 3 + "4" + 5, 1 + "2" + 3 + "4" + "5", 1 + "2" + "3" + 4 + 5, 1 + "2" + "3" + 4 + "5", 1 + "2" + "3" + "4" + 5, 1 + "2" + "3" + "4" + "5" ); } expect_stdout: true } concat_5: { options = {}; input: { console.log( "1" + 2 + (3 + 4 + 5), "1" + 2 + (3 + 4 + "5"), "1" + 2 + (3 + "4" + 5), "1" + 2 + (3 + "4" + "5"), "1" + 2 + ("3" + 4 + 5), "1" + 2 + ("3" + 4 + "5"), "1" + 2 + ("3" + "4" + 5), "1" + 2 + ("3" + "4" + "5") ); } expect: { console.log( "1" + 2 + (3 + 4 + 5), "1" + 2 + (3 + 4) + "5", "1" + 2 + 3 + "4" + 5, "1" + 2 + 3 + "4" + "5", "1" + 2 + "3" + 4 + 5, "1" + 2 + "3" + 4 + "5", "1" + 2 + "3" + "4" + 5, "1" + 2 + "3" + "4" + "5" ); } expect_stdout: true } concat_6: { options = {}; input: { console.log( "1" + "2" + (3 + 4 + 5), "1" + "2" + (3 + 4 + "5"), "1" + "2" + (3 + "4" + 5), "1" + "2" + (3 + "4" + "5"), "1" + "2" + ("3" + 4 + 5), "1" + "2" + ("3" + 4 + "5"), "1" + "2" + ("3" + "4" + 5), "1" + "2" + ("3" + "4" + "5") ); } expect: { console.log( "1" + "2" + (3 + 4 + 5), "1" + "2" + (3 + 4) + "5", "1" + "2" + 3 + "4" + 5, "1" + "2" + 3 + "4" + "5", "1" + "2" + "3" + 4 + 5, "1" + "2" + "3" + 4 + "5", "1" + "2" + "3" + "4" + 5, "1" + "2" + "3" + "4" + "5" ); } expect_stdout: true } concat_7: { input: { console.log( "" + 1, "" + "1", "" + 1 + 2, "" + 1 + "2", "" + "1" + 2, "" + "1" + "2", "" + (x += "foo") ); } expect: { console.log( "" + 1, "1", "" + 1 + 2, 1 + "2", "1" + 2, "1" + "2", x += "foo" ); } expect_stdout: true } concat_8: { input: { console.log( 1 + "", "1" + "", 1 + 2 + "", 1 + "2" + "", "1" + 2 + "", "1" + "2" + "", (x += "foo") + "" ); } expect: { console.log( 1 + "", "1", 1 + 2 + "", 1 + "2", "1" + 2, "1" + "2", x += "foo" ); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/conditionals.js000066400000000000000000000535731312030606600212420ustar00rootroot00000000000000ifs_1: { options = { conditionals: true }; input: { if (foo) bar(); if (!foo); else bar(); if (foo); else bar(); if (foo); else; } expect: { foo&&bar(); foo&&bar(); foo||bar(); foo; } } ifs_2: { options = { conditionals: true }; input: { if (foo) { x(); } else if (bar) { y(); } else if (baz) { z(); } if (foo) { x(); } else if (bar) { y(); } else if (baz) { z(); } else { t(); } } expect: { foo ? x() : bar ? y() : baz && z(); foo ? x() : bar ? y() : baz ? z() : t(); } } ifs_3_should_warn: { options = { conditionals : true, dead_code : true, evaluate : true, booleans : true, side_effects : true, }; input: { var x, y; if (x && !(x + "1") && y) { // 1 var qq; foo(); } else { bar(); } if (x || !!(x + "1") || y) { // 2 foo(); } else { var jj; bar(); } } expect: { var x, y; var qq; bar(); // 1 var jj; foo(); // 2 } } ifs_4: { options = { conditionals: true }; input: { if (foo && bar) { x(foo)[10].bar.baz = something(); } else x(foo)[10].bar.baz = something_else(); } expect: { foo && bar ? x(foo)[10].bar.baz = something() : x(foo)[10].bar.baz = something_else(); } } ifs_5: { options = { if_return: true, conditionals: true, comparisons: true, }; input: { function f() { if (foo) return; bar(); baz(); } function g() { if (foo) return; if (bar) return; if (baz) return; if (baa) return; a(); b(); } } expect: { function f() { if (!foo) { bar(); baz(); } } function g() { if (!(foo || bar || baz || baa)) { a(); b(); } } } } ifs_6: { options = { conditionals: true, comparisons: true }; input: { var x, y; if (!foo && !bar && !baz && !boo) { x = 10; } else { x = 20; } if (y) { x[foo] = 10; } else { x[foo] = 20; } if (foo) { x[bar] = 10; } else { x[bar] = 20; } } expect: { var x, y; x = foo || bar || baz || boo ? 20 : 10; x[foo] = y ? 10 : 20; foo ? x[bar] = 10 : x[bar] = 20; } } cond_1: { options = { conditionals: true }; input: { var do_something; // if undeclared it's assumed to have side-effects if (some_condition()) { do_something(x); } else { do_something(y); } if (some_condition()) { side_effects(x); } else { side_effects(y); } } expect: { var do_something; do_something(some_condition() ? x : y); some_condition() ? side_effects(x) : side_effects(y); } } cond_2: { options = { conditionals: true }; input: { var x, FooBar; if (some_condition()) { x = new FooBar(1); } else { x = new FooBar(2); } } expect: { var x, FooBar; x = new FooBar(some_condition() ? 1 : 2); } } cond_3: { options = { conditionals: true }; input: { var FooBar; if (some_condition()) { new FooBar(1); } else { FooBar(2); } } expect: { var FooBar; some_condition() ? new FooBar(1) : FooBar(2); } } cond_4: { options = { conditionals: true }; input: { var do_something; if (some_condition()) { do_something(); } else { do_something(); } if (some_condition()) { side_effects(); } else { side_effects(); } } expect: { var do_something; some_condition(), do_something(); some_condition(), side_effects(); } } cond_5: { options = { conditionals: true }; input: { if (some_condition()) { if (some_other_condition()) { do_something(); } else { alternate(); } } else { alternate(); } if (some_condition()) { if (some_other_condition()) { do_something(); } } } expect: { some_condition() && some_other_condition() ? do_something() : alternate(); some_condition() && some_other_condition() && do_something(); } } cond_7: { options = { conditionals: true, evaluate : true, side_effects: true, }; input: { var x, y, z, a, b; // compress these if (y) { x = 1+1; } else { x = 2; } if (y) { x = 1+1; } else if (z) { x = 2; } else { x = 3-1; } x = y ? 'foo' : 'fo'+'o'; x = y ? 'foo' : y ? 'foo' : 'fo'+'o'; // Compress conditions that have side effects if (condition()) { x = 10+10; } else { x = 20; } if (z) { x = 'fuji'; } else if (condition()) { x = 'fu'+'ji'; } else { x = 'fuji'; } x = condition() ? 'foobar' : 'foo'+'bar'; // don't compress these x = y ? a : b; x = y ? 'foo' : 'fo'; } expect: { var x, y, z, a, b; x = 2; x = 2; x = 'foo'; x = 'foo'; x = (condition(), 20); x = z ? 'fuji' : (condition(), 'fuji'); x = (condition(), 'foobar'); x = y ? a : b; x = y ? 'foo' : 'fo'; } } cond_7_1: { options = { conditionals: true, evaluate : true }; input: { var x; // access to global should be assumed to have side effects if (y) { x = 1+1; } else { x = 2; } } expect: { var x; x = (y, 2); } } cond_8: { options = { conditionals: true, evaluate : true, booleans : false }; input: { var a; // compress these a = condition ? true : false; a = !condition ? true : false; a = condition() ? true : false; a = condition ? !0 : !1; a = !condition ? !null : !2; a = condition() ? !0 : !-3.5; if (condition) { a = true; } else { a = false; } if (condition) { a = !0; } else { a = !1; } a = condition ? false : true; a = !condition ? false : true; a = condition() ? false : true; a = condition ? !3 : !0; a = !condition ? !2 : !0; a = condition() ? !1 : !0; if (condition) { a = false; } else { a = true; } if (condition) { a = !1; } else { a = !0; } // don't compress these a = condition ? 1 : false; a = !condition ? true : 0; a = condition ? 1 : 0; } expect: { var a; a = !!condition; a = !condition; a = !!condition(); a = !!condition; a = !condition; a = !!condition(); a = !!condition; a = !!condition; a = !condition; a = !!condition; a = !condition(); a = !condition; a = !!condition; a = !condition(); a = !condition; a = !condition; a = !!condition && 1; a = !condition || 0; a = condition ? 1 : 0; } } cond_8b: { options = { conditionals: true, evaluate : true, booleans : true }; input: { var a; // compress these a = condition ? true : false; a = !condition ? true : false; a = condition() ? true : false; a = condition ? !0 : !1; a = !condition ? !null : !2; a = condition() ? !0 : !-3.5; if (condition) { a = true; } else { a = false; } if (condition) { a = !0; } else { a = !1; } a = condition ? false : true; a = !condition ? false : true; a = condition() ? false : true; a = condition ? !3 : !0; a = !condition ? !2 : !0; a = condition() ? !1 : !0; if (condition) { a = false; } else { a = true; } if (condition) { a = !1; } else { a = !0; } a = condition ? 1 : false; a = !condition ? true : 0; a = condition ? 1 : 0; } expect: { var a; a = !!condition; a = !condition; a = !!condition(); a = !!condition; a = !condition; a = !!condition(); a = !!condition; a = !!condition; a = !condition; a = !!condition; a = !condition(); a = !condition; a = !!condition; a = !condition(); a = !condition; a = !condition; a = !!condition && 1; a = !condition || 0; a = condition ? 1 : 0; } } cond_8c: { options = { conditionals: true, evaluate : false, booleans : false }; input: { var a; // compress these a = condition ? true : false; a = !condition ? true : false; a = condition() ? true : false; a = condition ? !0 : !1; a = !condition ? !null : !2; a = condition() ? !0 : !-3.5; if (condition) { a = true; } else { a = false; } if (condition) { a = !0; } else { a = !1; } a = condition ? false : true; a = !condition ? false : true; a = condition() ? false : true; a = condition ? !3 : !0; a = !condition ? !2 : !0; a = condition() ? !1 : !0; if (condition) { a = false; } else { a = true; } if (condition) { a = !1; } else { a = !0; } a = condition ? 1 : false; a = !condition ? true : 0; a = condition ? 1 : 0; } expect: { var a; a = !!condition; a = !condition; a = !!condition(); a = !!condition; a = !condition; a = !!condition() || !-3.5; a = !!condition; a = !!condition; a = !condition; a = !!condition; a = !condition(); a = !condition; a = !!condition; a = !condition(); a = !condition; a = !condition; a = !!condition && 1; a = !condition || 0; a = condition ? 1 : 0; } } ternary_boolean_consequent: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { return a == b ? true : x; } function f2() { return a == b ? false : x; } function f3() { return a < b ? !0 : x; } function f4() { return a < b ? !1 : x; } function f5() { return c ? !0 : x; } function f6() { return c ? false : x; } function f7() { return !c ? true : x; } function f8() { return !c ? !1 : x; } } expect: { function f1() { return a == b || x; } function f2() { return a != b && x; } function f3() { return a < b || x; } function f4() { return !(a < b) && x; } function f5() { return !!c || x; } function f6() { return !c && x; } function f7() { return !c || x; } function f8() { return !!c && x; } } } ternary_boolean_alternative: { options = { collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { return a == b ? x : true; } function f2() { return a == b ? x : false; } function f3() { return a < b ? x : !0; } function f4() { return a < b ? x : !1; } function f5() { return c ? x : true; } function f6() { return c ? x : !1; } function f7() { return !c ? x : !0; } function f8() { return !c ? x : false; } } expect: { function f1() { return a != b || x; } function f2() { return a == b && x; } function f3() { return !(a < b) || x; } function f4() { return a < b && x; } function f5() { return !c || x; } function f6() { return !!c && x; } function f7() { return !!c || x; } function f8() { return !c && x; } } } trivial_boolean_ternary_expressions : { options = { conditionals: true, evaluate : true, booleans : true }; input: { f('foo' in m ? true : false); f('foo' in m ? false : true); f(g ? true : false); f(foo() ? true : false); f("bar" ? true : false); f(5 ? true : false); f(5.7 ? true : false); f(x - y ? true : false); f(x == y ? true : false); f(x === y ? !0 : !1); f(x < y ? !0 : false); f(x <= y ? true : false); f(x > y ? true : !1); f(x >= y ? !0 : !1); f(g ? false : true); f(foo() ? false : true); f("bar" ? false : true); f(5 ? false : true); f(5.7 ? false : true); f(x - y ? false : true); f(x == y ? !1 : !0); f(x === y ? false : true); f(x < y ? false : true); f(x <= y ? false : !0); f(x > y ? !1 : true); f(x >= y ? !1 : !0); } expect: { f('foo' in m); f(!('foo' in m)); f(!!g); f(!!foo()); f(!0); f(!0); f(!0); f(!!(x - y)); f(x == y); f(x === y); f(x < y); f(x <= y); f(x > y); f(x >= y); f(!g); f(!foo()); f(!1); f(!1); f(!1); f(!(x - y)); f(x != y); f(x !== y); f(!(x < y)); f(!(x <= y)); f(!(x > y)); f(!(x >= y)); } } issue_1154: { options = { conditionals: true, evaluate : true, booleans : true, side_effects: true, }; input: { function f1(x) { return x ? -1 : -1; } function f2(x) { return x ? +2 : +2; } function f3(x) { return x ? ~3 : ~3; } function f4(x) { return x ? !4 : !4; } function f5(x) { return x ? void 5 : void 5; } function f6(x) { return x ? typeof 6 : typeof 6; } function g1() { return g() ? -1 : -1; } function g2() { return g() ? +2 : +2; } function g3() { return g() ? ~3 : ~3; } function g4() { return g() ? !4 : !4; } function g5() { return g() ? void 5 : void 5; } function g6() { return g() ? typeof 6 : typeof 6; } } expect: { function f1(x) { return -1; } function f2(x) { return 2; } function f3(x) { return -4; } function f4(x) { return !1; } function f5(x) { return; } function f6(x) { return "number"; } function g1() { return g(), -1; } function g2() { return g(), 2; } function g3() { return g(), -4; } function g4() { return g(), !1; } function g5() { return void g(); } function g6() { return g(), "number"; } } } no_evaluate: { options = { conditionals: true, evaluate : false, side_effects: true, } input: { function f(b) { a = b ? !0 : !0; a = b ? ~1 : ~1; a = b ? -2 : -2; a = b ? +3 : +3; } } expect: { function f(b) { a = !0; a = ~1; a = -2; a = +3; } } } equality_conditionals_false: { options = { conditionals: false, sequences: true, } input: { function f(a, b, c) { console.log( a == (b ? a : a), a == (b ? a : c), a != (b ? a : a), a != (b ? a : c), a === (b ? a : a), a === (b ? a : c), a !== (b ? a : a), a !== (b ? a : c) ); } f(0, 0, 0); f(0, true, 0); f(1, 2, 3); f(1, null, 3); f(NaN); f(NaN, "foo"); } expect: { function f(a, b, c) { console.log( a == (b ? a : a), a == (b ? a : c), a != (b ? a : a), a != (b ? a : c), a === (b ? a : a), a === (b ? a : c), a !== (b ? a : a), a !== (b ? a : c) ); } f(0, 0, 0), f(0, true, 0), f(1, 2, 3), f(1, null, 3), f(NaN), f(NaN, "foo"); } expect_stdout: true } equality_conditionals_true: { options = { conditionals: true, sequences: true, } input: { function f(a, b, c) { console.log( a == (b ? a : a), a == (b ? a : c), a != (b ? a : a), a != (b ? a : c), a === (b ? a : a), a === (b ? a : c), a !== (b ? a : a), a !== (b ? a : c) ); } f(0, 0, 0); f(0, true, 0); f(1, 2, 3); f(1, null, 3); f(NaN); f(NaN, "foo"); } expect: { function f(a, b, c) { console.log( (b, a == a), a == (b ? a : c), (b, a != a), a != (b ? a : c), (b, a === a), a === (b ? a : c), (b, a !== a), a !== (b ? a : c) ); } f(0, 0, 0), f(0, true, 0), f(1, 2, 3), f(1, null, 3), f(NaN), f(NaN, "foo"); } expect_stdout: true } issue_1645_1: { options = { conditionals: true, } input: { var a = 100, b = 10; (b = a) ? a++ + (b += a) ? b += a : b += a : b ^= a; console.log(a, b); } expect: { var a = 100, b = 10; (b = a) ? (a++ + (b += a), b += a) : b ^= a; console.log(a,b); } expect_stdout: true } issue_1645_2: { options = { conditionals: true, } input: { var a = 0; function f() { return a++; } f() ? a += 2 : a += 4; console.log(a); } expect: { var a = 0; function f(){ return a++; } f() ? a += 2 : a += 4; console.log(a); } expect_stdout: true } condition_symbol_matches_consequent: { options = { conditionals: true, } input: { function foo(x, y) { return x ? x : y; } function bar() { return g ? g : h; } var g = 4; var h = 5; console.log(foo(3, null), foo(0, 7), foo(true, false), bar()); } expect: { function foo(x, y) { return x || y; } function bar() { return g || h; } var g = 4; var h = 5; console.log(foo(3, null), foo(0, 7), foo(true, false), bar()); } expect_stdout: "3 7 true 4" } delete_conditional_1: { options = { booleans: true, conditionals: true, evaluate: true, side_effects: true, } input: { console.log(delete (1 ? undefined : x)); console.log(delete (1 ? void 0 : x)); console.log(delete (1 ? Infinity : x)); console.log(delete (1 ? 1 / 0 : x)); console.log(delete (1 ? NaN : x)); console.log(delete (1 ? 0 / 0 : x)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((1 / 0, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((NaN, !0)); } expect_stdout: true } delete_conditional_2: { options = { booleans: true, conditionals: true, evaluate: true, keep_infinity: true, side_effects: true, } input: { console.log(delete (0 ? x : undefined)); console.log(delete (0 ? x : void 0)); console.log(delete (0 ? x : Infinity)); console.log(delete (0 ? x : 1 / 0)); console.log(delete (0 ? x : NaN)); console.log(delete (0 ? x : 0 / 0)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((Infinity, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((NaN, !0)); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/const.js000066400000000000000000000101041312030606600176610ustar00rootroot00000000000000issue_1191: { options = { evaluate : true, booleans : true, comparisons : true, dead_code : true, conditionals : true, side_effects : true, unused : true, hoist_funs : true, if_return : true, join_vars : true, sequences : false, collapse_vars : false, reduce_vars : true, } input: { function foo(rot) { const rotTol = 5; if (rot < -rotTol || rot > rotTol) bar(); baz(); } } expect: { function foo(rot) { (rot < -5 || rot > 5) && bar(); baz(); } } } issue_1194: { options = { evaluate : true, booleans : true, comparisons : true, dead_code : true, conditionals : true, side_effects : true, unused : true, hoist_funs : true, if_return : true, join_vars : true, sequences : false, collapse_vars : false, reduce_vars : true, } input: { function f1() {const a = "X"; return a + a;} function f2() {const aa = "X"; return aa + aa;} function f3() {const aaa = "X"; return aaa + aaa;} } expect: { function f1(){return"XX"} function f2(){return"XX"} function f3(){return"XX"} } } issue_1396: { options = { evaluate : true, booleans : true, comparisons : true, dead_code : true, conditionals : true, side_effects : true, unused : true, hoist_funs : true, if_return : true, join_vars : true, sequences : false, collapse_vars : false, reduce_vars : true, } input: { function foo(a) { const VALUE = 1; console.log(2 | VALUE); console.log(VALUE + 1); console.log(VALUE); console.log(a & VALUE); } function bar() { const s = "01234567890123456789"; console.log(s + s + s + s + s); const CONSTANT = "abc"; console.log(CONSTANT + CONSTANT + CONSTANT + CONSTANT + CONSTANT); } } expect: { function foo(a) { console.log(3); console.log(2); console.log(1); console.log(1 & a); } function bar() { const s = "01234567890123456789"; console.log(s + s + s + s + s); console.log("abcabcabcabcabc"); } } } unused_regexp_literal: { options = { evaluate : true, booleans : true, comparisons : true, dead_code : true, conditionals : true, side_effects : true, unused : true, hoist_funs : true, if_return : true, join_vars : true, sequences : false, collapse_vars : false, } input: { function f(){ var a = /b/; } } expect: { function f(){} } } regexp_literal_not_const: { options = { evaluate : true, booleans : true, comparisons : true, dead_code : true, conditionals : true, side_effects : true, unused : true, hoist_funs : true, if_return : true, join_vars : true, sequences : false, collapse_vars : false, reduce_vars : true, } input: { (function(){ var result; const s = 'acdabcdeabbb'; const REGEXP_LITERAL = /ab*/g; while (result = REGEXP_LITERAL.exec(s)) { console.log(result[0]); } })(); } expect: { (function() { var result; const REGEXP_LITERAL = /ab*/g; while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]); })(); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/dead-code.js000066400000000000000000000134041312030606600203460ustar00rootroot00000000000000dead_code_1: { options = { dead_code: true }; input: { function f() { a(); b(); x = 10; return; if (x) { y(); } } } expect: { function f() { a(); b(); x = 10; return; } } } dead_code_2_should_warn: { options = { dead_code: true }; input: { function f() { g(); x = 10; throw "foo"; // completely discarding the `if` would introduce some // bugs. UglifyJS v1 doesn't deal with this issue; in v2 // we copy any declarations to the upper scope. if (x) { y(); var x; function g(){}; // but nested declarations should not be kept. (function(){ var q; function y(){}; })(); } } } expect: { function f() { g(); x = 10; throw "foo"; var x; function g(){}; } } } dead_code_constant_boolean_should_warn_more: { options = { dead_code : true, loops : true, booleans : true, conditionals : true, evaluate : true, side_effects : true, }; input: { while (!((foo && bar) || (x + "0"))) { console.log("unreachable"); var foo; function bar() {} } for (var x = 10, y; x && (y || x) && (!typeof x); ++x) { asdf(); foo(); var moo; } } expect: { var foo; function bar() {} // nothing for the while // as for the for, it should keep: var x = 10, y; var moo; } expect_stdout: true } dead_code_const_declaration: { options = { dead_code : true, loops : true, booleans : true, conditionals : true, evaluate : true, reduce_vars : true, }; input: { var unused; const CONST_FOO = false; if (CONST_FOO) { console.log("unreachable"); var moo; function bar() {} } } expect: { var unused; const CONST_FOO = !1; var moo; function bar() {} } expect_stdout: true } dead_code_const_annotation: { options = { dead_code : true, loops : true, booleans : true, conditionals : true, evaluate : true, reduce_vars : true, toplevel : true, }; input: { var unused; /** @const */ var CONST_FOO_ANN = false; if (CONST_FOO_ANN) { console.log("unreachable"); var moo; function bar() {} } } expect: { var unused; var CONST_FOO_ANN = !1; var moo; function bar() {} } expect_stdout: true } dead_code_const_annotation_regex: { options = { dead_code : true, loops : true, booleans : true, conditionals : true, evaluate : true }; input: { var unused; // @constraint this shouldn't be a constant var CONST_FOO_ANN = false; if (CONST_FOO_ANN) { console.log("reachable"); } } expect: { var unused; var CONST_FOO_ANN = !1; CONST_FOO_ANN && console.log('reachable'); } expect_stdout: true } dead_code_const_annotation_complex_scope: { options = { dead_code : true, loops : true, booleans : true, conditionals : true, evaluate : true, reduce_vars : true, toplevel : true, }; input: { var unused_var; /** @const */ var test = 'test'; // @const var CONST_FOO_ANN = false; var unused_var_2; if (CONST_FOO_ANN) { console.log("unreachable"); var moo; function bar() {} } if (test === 'test') { var beef = 'good'; /** @const */ var meat = 'beef'; var pork = 'bad'; if (meat === 'pork') { console.log('also unreachable'); } else if (pork === 'good') { console.log('reached, not const'); } } } expect: { var unused_var; var test = 'test'; var CONST_FOO_ANN = !1; var unused_var_2; var moo; function bar() {} var beef = 'good'; var meat = 'beef'; var pork = 'bad'; } expect_stdout: true } try_catch_finally: { options = { conditionals: true, dead_code: true, evaluate: true, } input: { var a = 1; !function() { try { if (false) throw x; } catch (a) { var a = 2; console.log("FAIL"); } finally { a = 3; console.log("PASS"); } }(); try { console.log(a); } finally { } } expect: { var a = 1; !function() { var a; a = 3; console.log("PASS"); }(); try { console.log(a); } finally { } } expect_stdout: [ "PASS", "1", ] } accessor: { options = { side_effects: true, } input: { ({ get a() {}, set a(v){ this.b = 2; }, b: 1 }); } expect: {} } UglifyJS2-2.8.29/test/compress/debugger.js000066400000000000000000000004771312030606600203330ustar00rootroot00000000000000keep_debugger: { options = { drop_debugger: false }; input: { debugger; } expect: { debugger; } } drop_debugger: { options = { drop_debugger: true }; input: { debugger; if (foo) debugger; } expect: { if (foo); } } UglifyJS2-2.8.29/test/compress/drop-console.js000066400000000000000000000007671312030606600211550ustar00rootroot00000000000000drop_console_1: { options = {}; input: { console.log('foo'); console.log.apply(console, arguments); } expect: { console.log('foo'); console.log.apply(console, arguments); } } drop_console_2: { options = { drop_console: true }; input: { console.log('foo'); console.log.apply(console, arguments); } expect: { // with regular compression these will be stripped out as well void 0; void 0; } } UglifyJS2-2.8.29/test/compress/drop-unused.js000066400000000000000000000473371312030606600210220ustar00rootroot00000000000000unused_funarg_1: { options = { unused: true, keep_fargs: false }; input: { function f(a, b, c, d, e) { return a + b; } } expect: { function f(a, b) { return a + b; } } } unused_funarg_2: { options = { unused: true, keep_fargs: false }; input: { function f(a, b, c, d, e) { return a + c; } } expect: { function f(a, b, c) { return a + c; } } } unused_nested_function: { options = { unused: true }; input: { function f(x, y) { function g() { something(); } return x + y; } }; expect: { function f(x, y) { return x + y; } } } unused_circular_references_1: { options = { unused: true }; input: { function f(x, y) { // circular reference function g() { return h(); } function h() { return g(); } return x + y; } }; expect: { function f(x, y) { return x + y; } } } unused_circular_references_2: { options = { unused: true }; input: { function f(x, y) { var foo = 1, bar = baz, baz = foo + bar, qwe = moo(); return x + y; } }; expect: { function f(x, y) { moo(); // keeps side effect return x + y; } } } unused_circular_references_3: { options = { unused: true }; input: { function f(x, y) { var g = function() { return h() }; var h = function() { return g() }; return x + y; } }; expect: { function f(x, y) { return x + y; } } } unused_keep_setter_arg: { options = { unused: true }; input: { var x = { _foo: null, set foo(val) { }, get foo() { return this._foo; } } } expect: { var x = { _foo: null, set foo(val) { }, get foo() { return this._foo; } } } } unused_var_in_catch: { options = { unused: true }; input: { function foo() { try { foo(); } catch(ex) { var x = 10; } } } expect: { function foo() { try { foo(); } catch(ex) {} } } } used_var_in_catch: { options = { unused: true }; input: { function foo() { try { foo(); } catch(ex) { var x = 10; } return x; } } expect: { function foo() { try { foo(); } catch(ex) { var x = 10; } return x; } } } keep_fnames: { options = { unused: true, keep_fnames: true, unsafe: true }; input: { function foo() { return function bar(baz) {}; } } expect: { function foo() { return function bar(baz) {}; } } } drop_assign: { options = { unused: true }; input: { function f1() { var a; a = 1; } function f2() { var a = 1; a = 2; } function f3(a) { a = 1; } function f4() { var a; return a = 1; } function f5() { var a; return function() { a = 1; } } } expect: { function f1() { 1; } function f2() { 2; } function f3(a) { 1; } function f4() { return 1; } function f5() { var a; return function() { a = 1; } } } } keep_assign: { options = { unused: "keep_assign" }; input: { function f1() { var a; a = 1; } function f2() { var a = 1; a = 2; } function f3(a) { a = 1; } function f4() { var a; return a = 1; } function f5() { var a; return function() { a = 1; } } } expect: { function f1() { var a; a = 1; } function f2() { var a = 1; a = 2; } function f3(a) { a = 1; } function f4() { var a; return a = 1; } function f5() { var a; return function() { a = 1; } } } } drop_toplevel_funcs: { options = { toplevel: "funcs", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, b = 1, c = g; a = 2; function g() {} console.log(b = 3); } } drop_toplevel_vars: { options = { toplevel: "vars", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var c = g; function f(d) { return function() { c = 2; } } 2; function g() {} function h() {} console.log(3); } } drop_toplevel_vars_fargs: { options = { keep_fargs: false, toplevel: "vars", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var c = g; function f() { return function() { c = 2; } } 2; function g() {} function h() {} console.log(3); } } drop_toplevel_all: { options = { toplevel: true, unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { 2; console.log(3); } } drop_toplevel_retain: { options = { top_retain: "f,a,o", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} console.log(3); } } drop_toplevel_retain_array: { options = { top_retain: [ "f", "a", "o" ], unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} console.log(3); } } drop_toplevel_retain_regex: { options = { top_retain: /^[fao]$/, unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} console.log(3); } } drop_toplevel_all_retain: { options = { toplevel: true, top_retain: "f,a,o", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} console.log(3); } } drop_toplevel_funcs_retain: { options = { toplevel: "funcs", top_retain: "f,a,o", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} console.log(b = 3); } } drop_toplevel_vars_retain: { options = { toplevel: "vars", top_retain: "f,a,o", unused: true }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(3); } } drop_toplevel_keep_assign: { options = { toplevel: true, unused: "keep_assign" }; input: { var a, b = 1, c = g; function f(d) { return function() { c = 2; } } a = 2; function g() {} function h() {} console.log(b = 3); } expect: { var a, b = 1; a = 2; console.log(b = 3); } } drop_fargs: { options = { keep_fargs: false, unused: true, } input: { function f(a) { var b = a; } } expect: { function f() {} } } drop_fnames: { options = { keep_fnames: false, unused: true, } input: { function f() { return function g() { var a = g; }; } } expect: { function f() { return function() {}; } } } global_var: { options = { side_effects: true, unused: true, } input: { var a; function foo(b) { a; b; c; typeof c === "undefined"; c + b + a; b && b.ar(); return b; } } expect: { var a; function foo(b) { c; c; b && b.ar(); return b; } } } iife: { options = { side_effects: true, unused: true, } input: { function f() { var a; ~function() {}(b); } } expect: { function f() { b; } } } drop_value: { options = { side_effects: true, } input: { (1, [2, foo()], 3, {a:1, b:bar()}); } expect: { foo(), bar(); } } const_assign: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { function f() { const b = 2; return 1 + b; } function g() { const b = 2; b = 3; return 1 + b; } } expect: { function f() { return 3; } function g() { const b = 2; b = 3; return 1 + b; } } } issue_1539: { options = { cascade: true, sequences: true, side_effects: true, unused: true, } input: { function f() { var a, b; a = b = 42; return a; } } expect: { function f() { return 42; } } } vardef_value: { options = { keep_fnames: false, reduce_vars: true, unused: true, } input: { function f() { function g(){ return x(); } var a = g(); return a(42); } } expect: { function f() { var a = function(){ return x(); }(); return a(42); } } } assign_binding: { options = { cascade: true, side_effects: true, unused: true, } input: { function f() { var a; a = f.g, a(); } } expect: { function f() { (0, f.g)(); } } } assign_chain: { options = { unused: true, } input: { function f() { var a, b; x = a = y = b = 42; } } expect: { function f() { x = y = 42; } } } issue_1583: { options = { keep_fargs: true, reduce_vars: true, unused: true, } input: { function m(t) { (function(e) { t = e(); })(function() { return (function(a) { return a; })(function(a) {}); }); } } expect: { function m(t) { (function(e) { t = (function() { return (function(a) { return a; })(function(a) {}); })(); })(); } } } issue_1656: { options = { toplevel: true, unused: true, } beautify = { beautify: true, } input: { for(var a=0;;); } expect_exact: "for (;;) ;" } issue_1709: { options = { unused: true, } input: { console.log( function x() { var x = 1; return x; }(), function y() { const y = 2; return y; }(), function z() { function z() {} return z; }() ); } expect: { console.log( function() { var x = 1; return x; }(), function() { const y = 2; return y; }(), function() { function z() {} return z; }() ); } expect_stdout: true } issue_1715_1: { options = { unused: true, } input: { var a = 1; function f() { a++; try { x(); } catch (a) { var a; } } f(); console.log(a); } expect: { var a = 1; function f() { a++; try { x(); } catch (a) { var a; } } f(); console.log(a); } expect_stdout: "1" } issue_1715_2: { options = { unused: true, } input: { var a = 1; function f() { a++; try { x(); } catch (a) { var a = 2; } } f(); console.log(a); } expect: { var a = 1; function f() { a++; try { x(); } catch (a) { var a; } } f(); console.log(a); } expect_stdout: "1" } issue_1715_3: { options = { unused: true, } input: { var a = 1; function f() { a++; try { console; } catch (a) { var a = 2 + x(); } } f(); console.log(a); } expect: { var a = 1; function f() { a++; try { console; } catch (a) { var a = x(); } } f(); console.log(a); } expect_stdout: "1" } issue_1715_4: { options = { unused: true, } input: { var a = 1; !function a() { a++; try { x(); } catch (a) { var a; } }(); console.log(a); } expect: { var a = 1; !function() { a++; try { x(); } catch (a) { var a; } }(); console.log(a); } expect_stdout: "1" } delete_assign_1: { options = { booleans: true, side_effects: true, toplevel: true, unused: true, } input: { var a; console.log(delete (a = undefined)); console.log(delete (a = void 0)); console.log(delete (a = Infinity)); console.log(delete (a = 1 / 0)); console.log(delete (a = NaN)); console.log(delete (a = 0 / 0)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((1 / 0, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((0 / 0, !0)); } expect_stdout: true } delete_assign_2: { options = { booleans: true, keep_infinity: true, side_effects: true, toplevel: true, unused: true, } input: { var a; console.log(delete (a = undefined)); console.log(delete (a = void 0)); console.log(delete (a = Infinity)); console.log(delete (a = 1 / 0)); console.log(delete (a = NaN)); console.log(delete (a = 0 / 0)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((Infinity, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((0 / 0, !0)); } expect_stdout: true } issue_1830_1: { options = { unused: true, } input: { !function() { L: for (var b = console.log(1); !1;) continue L; }(); } expect: { !function() { L: for (console.log(1); !1;) continue L; }(); } expect_stdout: "1" } issue_1830_2: { options = { unused: true, } input: { !function() { L: for (var a = 1, b = console.log(a); --a;) continue L; }(); } expect: { !function() { var a = 1; L: for (console.log(a); --a;) continue L; }(); } expect_stdout: "1" } reassign_const: { options = { cascade: true, sequences: true, side_effects: true, unused: true, } input: { function f() { const a = 1; a = 2; return a; } console.log(f()); } expect: { function f() { const a = 1; return a = 2, a; } console.log(f()); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/evaluate.js000066400000000000000000000522231312030606600203510ustar00rootroot00000000000000and: { options = { evaluate: true } input: { var a; // compress these a = true && condition; a = 1 && console.log("a"); a = 2 * 3 && 2 * condition; a = 5 == 5 && condition + 3; a = "string" && 4 - condition; a = 5 + "" && condition / 5; a = -4.5 && 6 << condition; a = 6 && 7; a = false && condition; a = NaN && console.log("b"); a = 0 && console.log("c"); a = undefined && 2 * condition; a = null && condition + 3; a = 2 * 3 - 6 && 4 - condition; a = 10 == 7 && condition / 5; a = !"string" && 6 % condition; a = 0 && 7; // don't compress these a = condition && true; a = console.log("a") && 2; a = 4 - condition && "string"; a = 6 << condition && -4.5; a = condition && false; a = console.log("b") && NaN; a = console.log("c") && 0; a = 2 * condition && undefined; a = condition + 3 && null; } expect: { var a; a = condition; a = console.log("a"); a = 2 * condition; a = condition + 3; a = 4 - condition; a = condition / 5; a = 6 << condition; a = 7; a = false; a = NaN; a = 0; a = void 0; a = null; a = 0; a = false; a = false; a = 0; a = condition && true; a = console.log("a") && 2; a = 4 - condition && "string"; a = 6 << condition && -4.5; a = condition && false; a = console.log("b") && NaN; a = console.log("c") && 0; a = 2 * condition && void 0; a = condition + 3 && null; } } or: { options = { evaluate: true } input: { var a; // compress these a = true || condition; a = 1 || console.log("a"); a = 2 * 3 || 2 * condition; a = 5 == 5 || condition + 3; a = "string" || 4 - condition; a = 5 + "" || condition / 5; a = -4.5 || 6 << condition; a = 6 || 7; a = false || condition; a = 0 || console.log("b"); a = NaN || console.log("c"); a = undefined || 2 * condition; a = null || condition + 3; a = 2 * 3 - 6 || 4 - condition; a = 10 == 7 || condition / 5; a = !"string" || 6 % condition; a = null || 7; a = console.log(undefined && condition || null); a = console.log(undefined || condition && null); // don't compress these a = condition || true; a = console.log("a") || 2; a = 4 - condition || "string"; a = 6 << condition || -4.5; a = condition || false; a = console.log("b") || NaN; a = console.log("c") || 0; a = 2 * condition || undefined; a = condition + 3 || null; } expect: { var a; a = true; a = 1; a = 6; a = true; a = "string"; a = "5"; a = -4.5; a = 6; a = condition; a = console.log("b"); a = console.log("c"); a = 2 * condition; a = condition + 3; a = 4 - condition; a = condition / 5; a = 6 % condition; a = 7; a = console.log(null); a = console.log(condition && null); a = condition || true; a = console.log("a") || 2; a = 4 - condition || "string"; a = 6 << condition || -4.5; a = condition || false; a = console.log("b") || NaN; a = console.log("c") || 0; a = 2 * condition || void 0; a = condition + 3 || null; } } unary_prefix: { options = { evaluate: true } input: { a = !0 && b; a = !0 || b; a = ~1 && b; a = ~1 || b; a = -2 && b; a = -2 || b; a = +3 && b; a = +3 || b; } expect: { a = b; a = !0; a = b; a = -2; a = b; a = -2; a = b; a = 3; } } negative_zero: { options = { evaluate: true } input: { console.log( -"", - -"", 1 / (-0), 1 / (-"") ); } expect: { console.log( -0, 0, -1/0, -1/0 ); } expect_stdout: true } positive_zero: { options = { evaluate: true } input: { console.log( +"", + -"", 1 / (+0), 1 / (+"") ); } expect: { console.log( 0, -0, 1/0, 1/0 ); } expect_stdout: true } unsafe_constant: { options = { evaluate : true, unsafe : true } input: { console.log( true.a, false.a, null.a, undefined.a ); } expect: { console.log( true.a, false.a, null.a, (void 0).a ); } expect_stdout: true } unsafe_object: { options = { evaluate : true, unsafe : true } input: { console.log( ({a:1}) + 1, ({a:1}).a + 1, ({a:1}).b + 1, ({a:1}).a.b + 1 ); } expect: { console.log( ({a:1}) + 1, 2, ({a:1}).b + 1, 1..b + 1 ); } expect_stdout: true } unsafe_object_nested: { options = { evaluate : true, unsafe : true } input: { console.log( ({a:{b:1}}) + 1, ({a:{b:1}}).a + 1, ({a:{b:1}}).b + 1, ({a:{b:1}}).a.b + 1 ); } expect: { console.log( ({a:{b:1}}) + 1, ({a:{b:1}}).a + 1, ({a:{b:1}}).b + 1, 2 ); } expect_stdout: true } unsafe_object_complex: { options = { evaluate : true, unsafe : true } input: { console.log( ({a:{b:1},b:1}) + 1, ({a:{b:1},b:1}).a + 1, ({a:{b:1},b:1}).b + 1, ({a:{b:1},b:1}).a.b + 1 ); } expect: { console.log( ({a:{b:1},b:1}) + 1, ({a:{b:1},b:1}).a + 1, 2, 2 ); } expect_stdout: true } unsafe_object_repeated: { options = { evaluate : true, unsafe : true } input: { console.log( ({a:{b:1},a:1}) + 1, ({a:{b:1},a:1}).a + 1, ({a:{b:1},a:1}).b + 1, ({a:{b:1},a:1}).a.b + 1 ); } expect: { console.log( ({a:{b:1},a:1}) + 1, 2, ({a:{b:1},a:1}).b + 1, 1..b + 1 ); } expect_stdout: true } unsafe_object_accessor: { options = { evaluate: true, reduce_vars: true, unsafe: true, } input: { function f() { var a = { get b() {}, set b() {} }; return {a:a}; } } expect: { function f() { var a = { get b() {}, set b() {} }; return {a:a}; } } } unsafe_function: { options = { evaluate : true, unsafe : true } input: { console.log( ({a:{b:1},b:function(){}}) + 1, ({a:{b:1},b:function(){}}).a + 1, ({a:{b:1},b:function(){}}).b + 1, ({a:{b:1},b:function(){}}).a.b + 1 ); } expect: { console.log( ({a:{b:1},b:function(){}}) + 1, ({a:{b:1},b:function(){}}).a + 1, ({a:{b:1},b:function(){}}).b + 1, ({a:{b:1},b:function(){}}).a.b + 1 ); } expect_stdout: true } unsafe_integer_key: { options = { evaluate : true, unsafe : true } input: { console.log( ({0:1}) + 1, ({0:1})[0] + 1, ({0:1})["0"] + 1, ({0:1})[1] + 1, ({0:1})[0][1] + 1, ({0:1})[0]["1"] + 1 ); } expect: { console.log( ({0:1}) + 1, 2, 2, ({0:1})[1] + 1, 1[1] + 1, 1["1"] + 1 ); } expect_stdout: true } unsafe_integer_key_complex: { options = { evaluate : true, unsafe : true } input: { console.log( ({0:{1:1},1:1}) + 1, ({0:{1:1},1:1})[0] + 1, ({0:{1:1},1:1})["0"] + 1, ({0:{1:1},1:1})[1] + 1, ({0:{1:1},1:1})[0][1] + 1, ({0:{1:1},1:1})[0]["1"] + 1 ); } expect: { console.log( ({0:{1:1},1:1}) + 1, "[object Object]1", "[object Object]1", 2, 2, 2 ); } expect_stdout: true } unsafe_float_key: { options = { evaluate : true, unsafe : true } input: { console.log( ({2.72:1}) + 1, ({2.72:1})[2.72] + 1, ({2.72:1})["2.72"] + 1, ({2.72:1})[3.14] + 1, ({2.72:1})[2.72][3.14] + 1, ({2.72:1})[2.72]["3.14"] + 1 ); } expect: { console.log( ({2.72:1}) + 1, 2, 2, ({2.72:1})[3.14] + 1, 1[3.14] + 1, 1["3.14"] + 1 ); } expect_stdout: true } unsafe_float_key_complex: { options = { evaluate : true, unsafe : true } input: { console.log( ({2.72:{3.14:1},3.14:1}) + 1, ({2.72:{3.14:1},3.14:1})[2.72] + 1, ({2.72:{3.14:1},3.14:1})["2.72"] + 1, ({2.72:{3.14:1},3.14:1})[3.14] + 1, ({2.72:{3.14:1},3.14:1})[2.72][3.14] + 1, ({2.72:{3.14:1},3.14:1})[2.72]["3.14"] + 1 ); } expect: { console.log( "[object Object]1", "[object Object]1", "[object Object]1", 2, 2, 2 ); } expect_stdout: true } unsafe_array: { options = { evaluate : true, unsafe : true } input: { console.log( [1, , 3][1], [1, 2, 3, a] + 1, [1, 2, 3, 4] + 1, [1, 2, 3, a][0] + 1, [1, 2, 3, 4][0] + 1, [1, 2, 3, 4][6 - 5] + 1, [1, , 3, 4][6 - 5] + 1, [[1, 2], [3, 4]][0] + 1, [[1, 2], [3, 4]][6 - 5][1] + 1, [[1, 2], , [3, 4]][6 - 5][1] + 1 ); } expect: { console.log( void 0, [1, 2, 3, a] + 1, "1,2,3,41", [1, 2, 3, a][0] + 1, 2, 3, NaN, "1,21", 5, (void 0)[1] + 1 ); } expect_stdout: true } unsafe_string: { options = { evaluate : true, unsafe : true } input: { console.log( "1234" + 1, "1234"[0] + 1, "1234"[6 - 5] + 1, ("12" + "34")[0] + 1, ("12" + "34")[6 - 5] + 1, [1, 2, 3, 4].join("")[0] + 1 ); } expect: { console.log( "12341", "11", "21", "11", "21", "11" ); } expect_stdout: true } unsafe_array_bad_index: { options = { evaluate : true, unsafe : true } input: { console.log( [1, 2, 3, 4].a + 1, [1, 2, 3, 4]["a"] + 1, [1, 2, 3, 4][3.14] + 1 ); } expect: { console.log( [1, 2, 3, 4].a + 1, [1, 2, 3, 4]["a"] + 1, [1, 2, 3, 4][3.14] + 1 ); } expect_stdout: true } unsafe_string_bad_index: { options = { evaluate : true, unsafe : true } input: { console.log( "1234".a + 1, "1234"["a"] + 1, "1234"[3.14] + 1 ); } expect: { console.log( "1234".a + 1, "1234"["a"] + 1, "1234"[3.14] + 1 ); } expect_stdout: true } unsafe_prototype_function: { options = { evaluate : true, unsafe : true } input: { var a = ({valueOf: 0}) < 1; var b = ({toString: 0}) < 1; var c = ({valueOf: 0}) + ""; var d = ({toString: 0}) + ""; var e = (({valueOf: 0}) + "")[2]; var f = (({toString: 0}) + "")[2]; var g = ({valueOf: 0}).valueOf(); var h = ({toString: 0}).toString(); } expect: { var a = ({valueOf: 0}) < 1; var b = ({toString: 0}) < 1; var c = ({valueOf: 0}) + ""; var d = ({toString: 0}) + ""; var e = (({valueOf: 0}) + "")[2]; var f = (({toString: 0}) + "")[2]; var g = ({valueOf: 0}).valueOf(); var h = "" + ({toString: 0}); } } call_args: { options = { evaluate: true, reduce_vars: true, } input: { const a = 1; console.log(a); +function(a) { return a; }(a); } expect: { const a = 1; console.log(1); +(1, 1); } expect_stdout: true } call_args_drop_param: { options = { evaluate: true, keep_fargs: false, reduce_vars: true, unused: true, } input: { const a = 1; console.log(a); +function(a) { return a; }(a, b); } expect: { const a = 1; console.log(1); +(b, 1); } expect_stdout: true } in_boolean_context: { options = { booleans: true, evaluate: true, sequences: true, side_effects: true, } input: { console.log( !42, !"foo", ![1, 2], !/foo/, !b(42), !b("foo"), !b([1, 2]), !b(/foo/), ![1, foo()], ![1, foo(), 2] ); } expect: { console.log( !1, !1, !1, !1, !b(42), !b("foo"), !b([1, 2]), !b(/foo/), ![1, foo()], (foo(), !1) ); } expect_stdout: true } unsafe_charAt: { options = { evaluate : true, unsafe : true } input: { console.log( "1234" + 1, "1234".charAt(0) + 1, "1234".charAt(6 - 5) + 1, ("12" + "34").charAt(0) + 1, ("12" + "34").charAt(6 - 5) + 1, [1, 2, 3, 4].join("").charAt(0) + 1 ); } expect: { console.log( "12341", "11", "21", "11", "21", "11" ); } expect_stdout: true } unsafe_charAt_bad_index: { options = { evaluate : true, unsafe : true } input: { console.log( "1234".charAt() + 1, "1234".charAt("a") + 1, "1234".charAt(3.14) + 1 ); } expect: { console.log( "11", "11", "41" ); } expect_stdout: true } unsafe_charAt_noop: { options = { evaluate : true, unsafe : true } input: { console.log( s.charAt(0), "string".charAt(x) ); } expect: { console.log( s.charAt(0), "string".charAt(x) ); } } issue_1649: { options = { evaluate: true, } input: { console.log(-1 + -1); } expect: { console.log(-2); } expect_stdout: "-2"; } issue_1760_1: { options = { evaluate: true, } input: { !function(a) { try { throw 0; } catch (NaN) { a = +"foo"; } console.log(a); }(); } expect: { !function(a) { try { throw 0; } catch (NaN) { a = 0 / 0; } console.log(a); }(); } expect_stdout: "NaN" } issue_1760_2: { options = { evaluate: true, keep_infinity: true, } input: { !function(a) { try { throw 0; } catch (Infinity) { a = 123456789 / 0; } console.log(a); }(); } expect: { !function(a) { try { throw 0; } catch (Infinity) { a = 1 / 0; } console.log(a); }(); } expect_stdout: "Infinity" } delete_expr_1: { options = { booleans: true, evaluate: true, } input: { console.log(delete undefined); console.log(delete void 0); console.log(delete Infinity); console.log(delete (1 / 0)); console.log(delete NaN); console.log(delete (0 / 0)); } expect: { console.log(delete undefined); console.log((void 0, !0)); console.log(delete Infinity); console.log((1 / 0, !0)); console.log(delete NaN); console.log((0 / 0, !0)); } expect_stdout: true } delete_expr_2: { options = { booleans: true, evaluate: true, keep_infinity: true, } input: { console.log(delete undefined); console.log(delete void 0); console.log(delete Infinity); console.log(delete (1 / 0)); console.log(delete NaN); console.log(delete (0 / 0)); } expect: { console.log(delete undefined); console.log((void 0, !0)); console.log(delete Infinity); console.log((1 / 0, !0)); console.log(delete NaN); console.log((0 / 0, !0)); } expect_stdout: true } delete_binary_1: { options = { booleans: true, evaluate: true, side_effects: true, } input: { console.log(delete (true && undefined)); console.log(delete (true && void 0)); console.log(delete (true && Infinity)); console.log(delete (true && (1 / 0))); console.log(delete (true && NaN)); console.log(delete (true && (0 / 0))); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((1 / 0, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((NaN, !0)); } expect_stdout: true } delete_binary_2: { options = { booleans: true, evaluate: true, keep_infinity: true, side_effects: true, } input: { console.log(delete (false || undefined)); console.log(delete (false || void 0)); console.log(delete (false || Infinity)); console.log(delete (false || (1 / 0))); console.log(delete (false || NaN)); console.log(delete (false || (0 / 0))); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((Infinity, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((NaN, !0)); } expect_stdout: true } Infinity_NaN_undefined_LHS: { beautify = { beautify: true, } input: { function f() { Infinity = Infinity; ++Infinity; Infinity--; NaN *= NaN; ++NaN; NaN--; undefined |= undefined; ++undefined; undefined--; } } expect_exact: [ "function f() {", " Infinity = 1 / 0;", " ++Infinity;", " Infinity--;", " NaN *= NaN;", " ++NaN;", " NaN--;", " undefined |= void 0;", " ++undefined;", " undefined--;", "}", ] } issue_1964_1: { options = { evaluate: true, reduce_vars: true, unsafe_regexp: false, unused: true, } input: { function f() { var long_variable_name = /\s/; return "a b c".split(long_variable_name)[1]; } console.log(f()); } expect: { function f() { var long_variable_name = /\s/; return "a b c".split(long_variable_name)[1]; } console.log(f()); } expect_stdout: "b" } issue_1964_2: { options = { evaluate: true, reduce_vars: true, unsafe_regexp: true, unused: true, } input: { function f() { var long_variable_name = /\s/; return "a b c".split(long_variable_name)[1]; } console.log(f()); } expect: { function f() { return "a b c".split(/\s/)[1]; } console.log(f()); } expect_stdout: "b" } UglifyJS2-2.8.29/test/compress/functions.js000066400000000000000000000073251312030606600205560ustar00rootroot00000000000000non_ascii_function_identifier_name: { input: { function fooλ(δλ) {} function λ(δλ) {} (function λ(δλ) {})() } expect_exact: "function fooλ(δλ){}function λ(δλ){}(function λ(δλ){})();" } iifes_returning_constants_keep_fargs_true: { options = { keep_fargs : true, side_effects : true, evaluate : true, unused : true, dead_code : true, conditionals : true, comparisons : true, booleans : true, if_return : true, join_vars : true, reduce_vars : true, cascade : true, } input: { (function(){ return -1.23; }()); console.log( function foo(){ return "okay"; }() ); console.log( function foo(x, y, z){ return 123; }() ); console.log( function(x, y, z){ return z; }() ); console.log( function(x, y, z){ if (x) return y; return z; }(1, 2, 3) ); console.log( function(x, y){ return x * y; }(2, 3) ); console.log( function(x, y){ return x * y; }(2, 3, a(), b()) ); } expect: { console.log("okay"); console.log(123); console.log(void 0); console.log(2); console.log(6); console.log((a(), b(), 6)); } expect_stdout: true } iifes_returning_constants_keep_fargs_false: { options = { keep_fargs : false, side_effects : true, evaluate : true, unused : true, dead_code : true, conditionals : true, comparisons : true, booleans : true, if_return : true, join_vars : true, reduce_vars : true, cascade : true, } input: { (function(){ return -1.23; }()); console.log( function foo(){ return "okay"; }() ); console.log( function foo(x, y, z){ return 123; }() ); console.log( function(x, y, z){ return z; }() ); console.log( function(x, y, z){ if (x) return y; return z; }(1, 2, 3) ); console.log( function(x, y){ return x * y; }(2, 3) ); console.log( function(x, y){ return x * y; }(2, 3, a(), b()) ); } expect: { console.log("okay"); console.log(123); console.log(void 0); console.log(2); console.log(6); console.log((a(), b(), 6)); } expect_stdout: true } issue_485_crashing_1530: { options = { conditionals: true, dead_code: true, evaluate: true, } input: { (function(a) { if (true) return; var b = 42; })(this); } expect: { this, void 0; } } issue_1841_1: { options = { keep_fargs: false, pure_getters: "strict", reduce_vars: true, unused: true, } input: { var b = 10; !function(arg) { for (var key in "hi") var n = arg.baz, n = [ b = 42 ]; }(--b); console.log(b); } expect: { var b = 10; !function() { for (var key in "hi") { b = 42; } }(--b); console.log(b); } expect_exact: "42" } issue_1841_2: { options = { keep_fargs: false, pure_getters: false, reduce_vars: true, unused: true, } input: { var b = 10; !function(arg) { for (var key in "hi") var n = arg.baz, n = [ b = 42 ]; }(--b); console.log(b); } expect: { var b = 10; !function(arg) { for (var key in "hi") { arg.baz, b = 42; } }(--b); console.log(b); } expect_exact: "42" } UglifyJS2-2.8.29/test/compress/global_defs.js000066400000000000000000000067541312030606600210140ustar00rootroot00000000000000must_replace: { options = { global_defs: { D: "foo bar", } } input: { console.log(D); } expect: { console.log("foo bar"); } } keyword: { options = { global_defs: { undefined: 0, NaN: 1, Infinity: 2, }, } input: { console.log(undefined, NaN, Infinity); } expect: { console.log(0, 1, 2); } } object: { options = { evaluate: true, global_defs: { CONFIG: { DEBUG: [ 0 ], VALUE: 42, }, }, unsafe: true, } input: { function f(CONFIG) { // CONFIG not global - do not replace return CONFIG.VALUE; } function g() { var CONFIG = { VALUE: 1 }; // CONFIG not global - do not replace return CONFIG.VALUE; } function h() { return CONFIG.VALUE; } if (CONFIG.DEBUG[0]) console.debug("foo"); } expect: { function f(CONFIG) { return CONFIG.VALUE; } function g() { var CONFIG = { VALUE: 1 }; return CONFIG.VALUE; } function h() { return 42; } if (0) console.debug("foo"); } } expanded: { options = { global_defs: { "CONFIG.DEBUG": [ 0 ], "CONFIG.VALUE": 42, }, } input: { function f(CONFIG) { // CONFIG not global - do not replace return CONFIG.VALUE; } function g() { var CONFIG = { VALUE: 1 }; // CONFIG not global - do not replace return CONFIG.VALUE; } function h() { return CONFIG.VALUE; } if (CONFIG.DEBUG[0]) console.debug("foo"); } expect: { function f(CONFIG) { return CONFIG.VALUE; } function g() { var CONFIG = { VALUE: 1 }; return CONFIG.VALUE; } function h() { return 42; } if ([0][0]) console.debug("foo"); } } mixed: { options = { evaluate: true, global_defs: { "CONFIG.VALUE": 42, "FOO.BAR": "moo", }, properties: true, } input: { const FOO = { BAR: 0 }; console.log(FOO.BAR); console.log(++CONFIG.DEBUG); console.log(++CONFIG.VALUE); console.log(++CONFIG["VAL" + "UE"]); console.log(++DEBUG[CONFIG.VALUE]); CONFIG.VALUE.FOO = "bar"; console.log(CONFIG); } expect: { const FOO = { BAR: 0 }; console.log("moo"); console.log(++CONFIG.DEBUG); console.log(++CONFIG.VALUE); console.log(++CONFIG.VALUE); console.log(++DEBUG[42]); CONFIG.VALUE.FOO = "bar"; console.log(CONFIG); } expect_warnings: [ 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]', 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]', 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]', ] } issue_1801: { options = { booleans: true, global_defs: { "CONFIG.FOO.BAR": true, }, } input: { console.log(CONFIG.FOO.BAR); } expect: { console.log(!0); } } UglifyJS2-2.8.29/test/compress/hoist_vars.js000066400000000000000000000032101312030606600207140ustar00rootroot00000000000000statements: { options = { hoist_funs: false, hoist_vars: true, } input: { function f() { var a = 1; var b = 2; var c = 3; function g() {} return g(a, b, c); } } expect: { function f() { var a = 1, b = 2, c = 3; function g() {} return g(a, b, c); } } } statements_funs: { options = { hoist_funs: true, hoist_vars: true, } input: { function f() { var a = 1; var b = 2; var c = 3; function g() {} return g(a, b, c); } } expect: { function f() { function g() {} var a = 1, b = 2, c = 3; return g(a, b, c); } } } sequences: { options = { hoist_funs: false, hoist_vars: true, } input: { function f() { var a = 1, b = 2; function g() {} var c = 3; return g(a, b, c); } } expect: { function f() { var c, a = 1, b = 2; function g() {} c = 3; return g(a, b, c); } } } sequences_funs: { options = { hoist_funs: true, hoist_vars: true, } input: { function f() { var a = 1, b = 2; function g() {} var c = 3; return g(a, b, c); } } expect: { function f() { function g() {} var a = 1, b = 2, c = 3; return g(a, b, c); } } } UglifyJS2-2.8.29/test/compress/html_comments.js000066400000000000000000000025031312030606600214100ustar00rootroot00000000000000html_comment_in_expression: { input: { function f(a, b, x, y) { return a < !--b && x-- > y; } } expect_exact: "function f(a,b,x,y){return a< !--b&&x-- >y}"; } html_comment_in_less_than: { input: { function f(a, b) { return a < !--b; } } expect_exact: "function f(a,b){return a< !--b}"; } html_comment_in_left_shift: { input: { function f(a, b) { return a << !--b; } } expect_exact: "function f(a,b){return a<< !--b}"; } html_comment_in_right_shift: { input: { function f(a, b) { return a-- >> b; } } expect_exact: "function f(a,b){return a-- >>b}"; } html_comment_in_zero_fill_right_shift: { input: { function f(a, b) { return a-- >>> b; } } expect_exact: "function f(a,b){return a-- >>>b}"; } html_comment_in_greater_than: { input: { function f(a, b) { return a-- > b; } } expect_exact: "function f(a,b){return a-- >b}"; } html_comment_in_greater_than_or_equal: { input: { function f(a, b) { return a-- >= b; } } expect_exact: "function f(a,b){return a-- >=b}"; } html_comment_in_string_literal: { input: { function f() { return "comment in"; } } expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}'; } UglifyJS2-2.8.29/test/compress/if_return.js000066400000000000000000000145651312030606600205470ustar00rootroot00000000000000if_return_1: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f(x) { if (x) { return true; } } } expect: { function f(x){if(x)return!0} } } if_return_2: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f(x, y) { if (x) return 3; if (y) return c(); } } expect: { function f(x,y){return x?3:y?c():void 0} } } if_return_3: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f(x) { a(); if (x) { b(); return false; } } } expect: { function f(x){if(a(),x)return b(),!1} } } if_return_4: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f(x, y) { a(); if (x) return 3; b(); if (y) return c(); } } expect: { function f(x,y){return a(),x?3:(b(),y?c():void 0)} } } if_return_5: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f() { if (x) return; return 7; if (y) return j; } } expect: { function f(){if(!x)return 7} } } if_return_6: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f(x) { return x ? true : void 0; return y; } } expect: { // suboptimal function f(x){return!!x||void 0} } } if_return_7: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function f(x) { if (x) { return true; } foo(); bar(); } } expect: { function f(x){if(x)return!0;foo(),bar()} } } if_return_8: { options = { if_return: true, sequences: true, conditionals: true, side_effects : true, } input: { function f(e) { if (2 == e) return foo(); if (3 == e) return bar(); if (4 == e) return baz(); fail(e); } function g(e) { if (a(e)) return foo(); if (b(e)) return bar(); if (c(e)) return baz(); fail(e); } function h(e) { if (a(e)) return foo(); else if (b(e)) return bar(); else if (c(e)) return baz(); else fail(e); } function i(e) { if (a(e)) return foo(); else if (b(e)) return bar(); else if (c(e)) return baz(); fail(e); } } expect: { function f(e){return 2==e?foo():3==e?bar():4==e?baz():void fail(e)} function g(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)} function h(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)} function i(e){return a(e)?foo():b(e)?bar():c(e)?baz():void fail(e)} } } issue_1089: { options = { if_return : true, sequences : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, unused : true, side_effects : true, dead_code : true, } input: { function x() { var f = document.getElementById("fname"); if (f.files[0].size > 12345) { alert("alert"); f.focus(); return false; } } } expect: { function x() { var f = document.getElementById("fname"); if (f.files[0].size > 12345) return alert("alert"), f.focus(), !1; } } } issue_1437: { options = { if_return : true, sequences : true, conditionals : false } input: { function x() { if (a()) return b(); if (c()) return d(); else e(); f(); } } expect: { function x() { if (a()) return b(); if (c()) return d(); else e() f(); } } } issue_1437_conditionals: { options = { conditionals : true, if_return : true, sequences : true } input: { function x() { if (a()) return b(); if (c()) return d(); else e(); f(); } } expect: { function x() { return a() ? b() : c() ? d() : (e(), f(), void 0); } } } UglifyJS2-2.8.29/test/compress/issue-1034.js000066400000000000000000000104131312030606600202530ustar00rootroot00000000000000non_hoisted_function_after_return: { options = { hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, if_return: true, join_vars: true, cascade: true, side_effects: true } input: { function foo(x) { if (x) { return bar(); not_called1(); } else { return baz(); not_called2(); } function bar() { return 7; } return not_reached; function UnusedFunction() {} function baz() { return 8; } } } expect: { function foo(x) { return x ? bar() : baz(); function bar() { return 7 } function baz() { return 8 } } } expect_warnings: [ 'WARN: Dropping unreachable code [test/compress/issue-1034.js:11,16]', "WARN: Dropping unreachable code [test/compress/issue-1034.js:14,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:17,12]", "WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:18,21]" ] } non_hoisted_function_after_return_2a: { options = { hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, if_return: true, join_vars: true, cascade: true, side_effects: true, collapse_vars: false, passes: 2, warnings: "verbose" } input: { function foo(x) { if (x) { return bar(1); var a = not_called(1); } else { return bar(2); var b = not_called(2); } var c = bar(3); function bar(x) { return 7 - x; } function nope() {} return b || c; } } expect: { function foo(x) { return bar(x ? 1 : 2); function bar(x) { return 7 - x; } } } expect_warnings: [ "WARN: Dropping unreachable code [test/compress/issue-1034.js:48,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:48,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]", "WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]", "WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]", ] } non_hoisted_function_after_return_2b: { options = { hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, if_return: true, join_vars: true, cascade: true, side_effects: true, collapse_vars: false } input: { function foo(x) { if (x) { return bar(1); } else { return bar(2); var b; } var c = bar(3); function bar(x) { return 7 - x; } return b || c; } } expect: { function foo(x) { return bar(x ? 1 : 2); function bar(x) { return 7 - x; } } } expect_warnings: [ // duplicate warnings no longer emitted "WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]", ] } UglifyJS2-2.8.29/test/compress/issue-1041.js000066400000000000000000000011321312030606600202470ustar00rootroot00000000000000const_declaration: { options = { evaluate: true }; input: { const goog = goog || {}; } expect: { const goog = goog || {}; } } const_pragma: { options = { evaluate: true, reduce_vars: true, }; input: { /** @const */ var goog = goog || {}; } expect: { var goog = goog || {}; } } // for completeness' sake not_const: { options = { evaluate: true, reduce_vars: true, }; input: { var goog = goog || {}; } expect: { var goog = goog || {}; } } UglifyJS2-2.8.29/test/compress/issue-1052.js000066400000000000000000000035331312030606600202600ustar00rootroot00000000000000multiple_functions: { options = { if_return: true, hoist_funs: false }; input: { ( function() { if ( !window ) { return; } function f() {} function g() {} } )(); } expect: { ( function() { function f() {} function g() {} // NOTE: other compression steps will reduce this // down to just `window`. if ( window ); } )(); } } single_function: { options = { if_return: true, hoist_funs: false }; input: { ( function() { if ( !window ) { return; } function f() {} } )(); } expect: { ( function() { function f() {} if ( window ); } )(); } } deeply_nested: { options = { if_return: true, hoist_funs: false }; input: { ( function() { if ( !window ) { return; } function f() {} function g() {} if ( !document ) { return; } function h() {} } )(); } expect: { ( function() { function f() {} function g() {} function h() {} // NOTE: other compression steps will reduce this // down to just `window`. if ( window ) if (document); } )(); } } not_hoisted_when_already_nested: { options = { if_return: true, hoist_funs: false }; input: { ( function() { if ( !window ) { return; } if ( foo ) function f() {} } )(); } expect: { ( function() { if ( window ) if ( foo ) function f() {} } )(); } } UglifyJS2-2.8.29/test/compress/issue-1105.js000066400000000000000000000157651312030606600202710ustar00rootroot00000000000000with_in_global_scope: { options = { unused: true } input: { var o = 42; with(o) { var foo = 'something' } doSomething(o); } expect: { var o=42; with(o) var foo = "something"; doSomething(o); } } with_in_function_scope: { options = { unused: true } input: { function foo() { var o = 42; with(o) { var foo = "something" } doSomething(o); } } expect: { function foo() { var o=42; with(o) var foo = "something"; doSomething(o) } } } compress_with_with_in_other_scope: { options = { unused: true } input: { function foo() { var o = 42; with(o) { var foo = "something" } doSomething(o); } function bar() { var unused = 42; return something(); } } expect: { function foo() { var o = 42; with(o) var foo = "something"; doSomething(o) } function bar() { return something() } } } with_using_existing_variable_outside_scope: { options = { unused: true } input: { function f() { var o = {}; var unused = {}; // Doesn't get removed because upper scope uses with function foo() { with(o) { var foo = "something" } doSomething(o); } foo() } } expect: { function f() { var o = {}; var unused = {}; function foo() { with(o) var foo = "something"; doSomething(o) } foo() } } } check_drop_unused_in_peer_function: { options = { unused: true } input: { function outer() { var o = {}; var unused = {}; // should be kept function foo() { // should be kept function not_in_use() { var nested_unused = "foo"; // should be dropped return 24; } var unused = {}; // should be kept with (o) { var foo = "something"; } doSomething(o); } function bar() { var unused = {}; // should be dropped doSomethingElse(); } foo(); bar(); } } expect: { function outer() { var o = {}; var unused = {}; // should be kept function foo() { // should be kept function not_in_use() { return 24; } var unused = {}; // should be kept with (o) var foo = "something"; doSomething(o); } function bar() { doSomethingElse(); } foo(); bar(); } } } Infinity_not_in_with_scope: { options = { unused: true } input: { var o = { Infinity: 'oInfinity' }; var vInfinity = "Infinity"; vInfinity = Infinity; } expect: { var o = { Infinity: 'oInfinity' } var vInfinity = "Infinity" vInfinity = 1/0 } } Infinity_in_with_scope: { options = { unused: true } input: { var o = { Infinity: 'oInfinity' }; var vInfinity = "Infinity"; with (o) { vInfinity = Infinity; } } expect: { var o = { Infinity: 'oInfinity' } var vInfinity = "Infinity" with (o) vInfinity = Infinity } } assorted_Infinity_NaN_undefined_in_with_scope: { options = { unused: true, evaluate: true, dead_code: true, conditionals: true, comparisons: true, booleans: true, hoist_funs: true, keep_fargs: true, if_return: true, join_vars: true, cascade: true, side_effects: true, sequences: false, keep_infinity: false, } input: { var f = console.log; var o = { undefined : 3, NaN : 4, Infinity : 5, }; if (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); f(-Infinity, -(1/0)); f(2 + 7 + undefined, 2 + 7 + void 0); } with (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); f(-Infinity, -(1/0)); f(2 + 7 + undefined, 2 + 7 + void 0); } } expect: { var f = console.log, o = { undefined : 3, NaN : 4, Infinity : 5 }; if (o) { f(void 0, void 0); f(NaN, NaN); f(1/0, 1/0); f(-1/0, -1/0); f(NaN, NaN); } with (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); f(-Infinity, -1/0); f(9 + undefined, 9 + void 0); } } expect_stdout: true } assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: { options = { unused: true, evaluate: true, dead_code: true, conditionals: true, comparisons: true, booleans: true, hoist_funs: true, keep_fargs: true, if_return: true, join_vars: true, cascade: true, side_effects: true, sequences: false, keep_infinity: true, } input: { var f = console.log; var o = { undefined : 3, NaN : 4, Infinity : 5, }; if (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); f(-Infinity, -(1/0)); f(2 + 7 + undefined, 2 + 7 + void 0); } with (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); f(-Infinity, -(1/0)); f(2 + 7 + undefined, 2 + 7 + void 0); } } expect: { var f = console.log, o = { undefined : 3, NaN : 4, Infinity : 5 }; if (o) { f(void 0, void 0); f(NaN, NaN); f(Infinity, 1/0); f(-Infinity, -1/0); f(NaN, NaN); } with (o) { f(undefined, void 0); f(NaN, 0/0); f(Infinity, 1/0); f(-Infinity, -1/0); f(9 + undefined, 9 + void 0); } } expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-12.js000066400000000000000000000024331312030606600201110ustar00rootroot00000000000000keep_name_of_getter: { options = { unused: true }; input: { a = { get foo () {} } } expect: { a = { get foo () {} } } } keep_name_of_setter: { options = { unused: true }; input: { a = { set foo () {} } } expect: { a = { set foo () {} } } } setter_with_operator_keys: { input: { var tokenCodes = { get instanceof(){ return test0; }, set instanceof(value){ test0 = value; }, set typeof(value){ test1 = value; }, get typeof(){ return test1; }, set else(value){ test2 = value; }, get else(){ return test2; } }; } expect: { var tokenCodes = { get instanceof(){ return test0; }, set instanceof(value){ test0 = value; }, set typeof(value){ test1 = value; }, get typeof(){ return test1; }, set else(value){ test2 = value; }, get else(){ return test2; } }; } }UglifyJS2-2.8.29/test/compress/issue-1202.js000066400000000000000000000017351312030606600202570ustar00rootroot00000000000000mangle_keep_fnames_false: { options = { keep_fnames : true, keep_fargs : true, } mangle = { keep_fnames : false, } input: { "use strict"; function total() { return function n(a, b, c) { return a + b + c; }; } } expect: { "use strict"; function total() { return function t(n, r, u) { return n + r + u; }; } } } mangle_keep_fnames_true: { options = { keep_fnames : true, keep_fargs : true, } mangle = { keep_fnames : true, } input: { "use strict"; function total() { return function n(a, b, c) { return a + b + c; }; } } expect: { "use strict"; function total() { return function n(t, r, u) { return t + r + u; }; } } } UglifyJS2-2.8.29/test/compress/issue-126.js000066400000000000000000000015071312030606600202000ustar00rootroot00000000000000concatenate_rhs_strings: { options = { evaluate: true, unsafe: true, } input: { foo(bar() + 123 + "Hello" + "World"); foo(bar() + (123 + "Hello") + "World"); foo((bar() + 123) + "Hello" + "World"); foo(bar() + 123 + "Hello" + "World" + ("Foo" + "Bar")); foo("Foo" + "Bar" + bar() + 123 + "Hello" + "World" + ("Foo" + "Bar")); foo("Hello" + bar() + 123 + "World"); foo(bar() + 'Foo' + (10 + parseInt('10'))); } expect: { foo(bar() + 123 + "HelloWorld"); foo(bar() + "123HelloWorld"); foo((bar() + 123) + "HelloWorld"); foo(bar() + 123 + "HelloWorldFooBar"); foo("FooBar" + bar() + "123HelloWorldFooBar"); foo("Hello" + bar() + "123World"); foo(bar() + 'Foo' + (10 + parseInt('10'))); } } UglifyJS2-2.8.29/test/compress/issue-1261.js000066400000000000000000000153011312030606600202560ustar00rootroot00000000000000pure_function_calls: { options = { evaluate : true, conditionals : true, comparisons : true, side_effects : true, booleans : true, unused : true, if_return : true, join_vars : true, cascade : true, negate_iife : true, } input: { // pure top-level IIFE will be dropped // @__PURE__ - comment (function() { console.log("iife0"); })(); // pure top-level IIFE assigned to unreferenced var will not be dropped var iife1 = /*@__PURE__*/(function() { console.log("iife1"); function iife1() {} return iife1; })(); (function(){ // pure IIFE in function scope assigned to unreferenced var will be dropped var iife2 = /*#__PURE__*/(function() { console.log("iife2"); function iife2() {} return iife2; })(); })(); // comment #__PURE__ comment bar(), baz(), quux(); a.b(), /* @__PURE__ */ c.d.e(), f.g(); } expect: { var iife1 = function() { console.log("iife1"); function iife1() {} return iife1; }(); baz(), quux(); a.b(), f.g(); } expect_warnings: [ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:17,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:17,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:30,37]", "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:30,16]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:28,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:39,31]", ] } pure_function_calls_toplevel: { options = { evaluate : true, conditionals : true, comparisons : true, side_effects : true, booleans : true, unused : true, if_return : true, join_vars : true, cascade : true, negate_iife : true, toplevel : true, } input: { // pure top-level IIFE will be dropped // @__PURE__ - comment (function() { console.log("iife0"); })(); // pure top-level IIFE assigned to unreferenced var will be dropped var iife1 = /*@__PURE__*/(function() { console.log("iife1"); function iife1() {} return iife1; })(); (function(){ // pure IIFE in function scope assigned to unreferenced var will be dropped var iife2 = /*#__PURE__*/(function() { console.log("iife2"); function iife2() {} return iife2; })(); })(); // comment #__PURE__ comment bar(), baz(), quux(); a.b(), /* @__PURE__ */ c.d.e(), f.g(); } expect: { baz(), quux(); a.b(), f.g(); } expect_warnings: [ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:79,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:79,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]", "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]", "WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]", ] } should_warn: { options = { booleans: true, conditionals: true, evaluate: true, side_effects: true, } input: { /* @__PURE__ */(function(){x})(), void/* @__PURE__ */(function(){y})(); /* @__PURE__ */(function(){x})() || true ? foo() : bar(); true || /* @__PURE__ */(function(){y})() ? foo() : bar(); /* @__PURE__ */(function(){x})() && false ? foo() : bar(); false && /* @__PURE__ */(function(){y})() ? foo() : bar(); /* @__PURE__ */(function(){x})() + "foo" ? bar() : baz(); "foo" + /* @__PURE__ */(function(){y})() ? bar() : baz(); /* @__PURE__ */(function(){x})() ? foo() : foo(); [/* @__PURE__ */(function(){x})()] ? foo() : bar(); !{ foo: /* @__PURE__ */(function(){x})() } ? bar() : baz(); } expect: { foo(); foo(); bar(); bar(); bar(); bar(); foo(); foo(); baz(); } expect_warnings: [ "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]", "WARN: Boolean || always true [test/compress/issue-1261.js:129,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]", "WARN: Condition always true [test/compress/issue-1261.js:129,23]", "WARN: Condition left of || always true [test/compress/issue-1261.js:130,8]", "WARN: Condition always true [test/compress/issue-1261.js:130,8]", "WARN: Boolean && always false [test/compress/issue-1261.js:131,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]", "WARN: Condition always false [test/compress/issue-1261.js:131,23]", "WARN: Condition left of && always false [test/compress/issue-1261.js:132,8]", "WARN: Condition always false [test/compress/issue-1261.js:132,8]", "WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]", "WARN: Condition always true [test/compress/issue-1261.js:133,23]", "WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]", "WARN: Condition always true [test/compress/issue-1261.js:134,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]", "WARN: Condition always true [test/compress/issue-1261.js:136,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]", "WARN: Condition always false [test/compress/issue-1261.js:137,8]", ] } UglifyJS2-2.8.29/test/compress/issue-1275.js000066400000000000000000000025521312030606600202670ustar00rootroot00000000000000string_plus_optimization: { options = { side_effects : true, evaluate : true, conditionals : true, comparisons : true, dead_code : true, booleans : true, unused : true, if_return : true, join_vars : true, cascade : true, hoist_funs : true, }; input: { function foo(anything) { function throwing_function() { throw "nope"; } try { console.log('0' + throwing_function() ? "yes" : "no"); } catch (ex) { console.log(ex); } console.log('0' + anything ? "yes" : "no"); console.log(anything + '0' ? "Yes" : "No"); console.log('' + anything); console.log(anything + ''); } foo(); } expect: { function foo(anything) { function throwing_function() { throw "nope"; } try { console.log((throwing_function(), "yes")); } catch (ex) { console.log(ex); } console.log("yes"); console.log("Yes"); console.log('' + anything); console.log(anything + ''); } foo(); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-1321.js000066400000000000000000000020631312030606600202540ustar00rootroot00000000000000issue_1321_no_debug: { mangle_props = { ignore_quoted: true } input: { var x = {}; x.foo = 1; x["a"] = 2 * x.foo; console.log(x.foo, x["a"]); } expect: { var x = {}; x.b = 1; x["a"] = 2 * x.b; console.log(x.b, x["a"]); } expect_stdout: true } issue_1321_debug: { mangle_props = { ignore_quoted: true, debug: "" } input: { var x = {}; x.foo = 1; x["_$foo$_"] = 2 * x.foo; console.log(x.foo, x["_$foo$_"]); } expect: { var x = {}; x.a = 1; x["_$foo$_"] = 2 * x.a; console.log(x.a, x["_$foo$_"]); } expect_stdout: true } issue_1321_with_quoted: { mangle_props = { ignore_quoted: false } input: { var x = {}; x.foo = 1; x["a"] = 2 * x.foo; console.log(x.foo, x["a"]); } expect: { var x = {}; x.a = 1; x["b"] = 2 * x.a; console.log(x.a, x["b"]); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-143.js000066400000000000000000000021101312030606600201660ustar00rootroot00000000000000/** * There was an incorrect sort behaviour documented in issue #143: * (x = f(…)) <= x → x >= (x = f(…)) * * For example, let the equation be: * (a = parseInt('100')) <= a * * If a was an integer and has the value of 99, * (a = parseInt('100')) <= a → 100 <= 100 → true * * When transformed incorrectly: * a >= (a = parseInt('100')) → 99 >= 100 → false */ tranformation_sort_order_equal: { options = { comparisons: true, }; input: { (a = parseInt('100')) == a } expect: { (a = parseInt('100')) == a } } tranformation_sort_order_unequal: { options = { comparisons: true, }; input: { (a = parseInt('100')) != a } expect: { (a = parseInt('100')) != a } } tranformation_sort_order_lesser_or_equal: { options = { comparisons: true, }; input: { (a = parseInt('100')) <= a } expect: { (a = parseInt('100')) <= a } } tranformation_sort_order_greater_or_equal: { options = { comparisons: true, }; input: { (a = parseInt('100')) >= a } expect: { (a = parseInt('100')) >= a } }UglifyJS2-2.8.29/test/compress/issue-1431.js000066400000000000000000000062741312030606600202660ustar00rootroot00000000000000level_zero: { options = { keep_fnames: true } mangle = { keep_fnames: true } input: { function f(x) { function n(a) { return a * a; } return function() { return x; }; } } expect: { function f(r) { function n(n) { return n * n; } return function() { return r; }; } } } level_one: { options = { keep_fnames: true } mangle = { keep_fnames: true } input: { function f(x) { return function() { function n(a) { return a * a; } return x(n); }; } } expect: { function f(r) { return function() { function n(n) { return n * n; } return r(n); }; } } } level_two: { options = { keep_fnames: true } mangle = { keep_fnames: true } input: { function f(x) { return function() { function r(a) { return a * a; } return function() { function n(a) { return a * a; } return x(n); }; }; } } expect: { function f(t) { return function() { function r(n) { return n * n; } return function() { function n(n) { return n * n; } return t(n); }; }; } } } level_three: { options = { keep_fnames: true } mangle = { keep_fnames: true } input: { function f(x) { return function() { function r(a) { return a * a; } return [ function() { function t(a) { return a * a; } return t; }, function() { function n(a) { return a * a; } return x(n); } ]; }; } } expect: { function f(t) { return function() { function r(n) { return n * n; } return [ function() { function t(n) { return n * n; } return t; }, function() { function n(n) { return n * n; } return t(n); } ]; }; } } } UglifyJS2-2.8.29/test/compress/issue-1443.js000066400000000000000000000023541312030606600202640ustar00rootroot00000000000000// tests assume that variable `undefined` not redefined and has `void 0` as value unsafe_undefined: { options = { conditionals: true, if_return: true, unsafe: true } mangle = {} input: { function f(undefined) { return function() { if (a) return b; if (c) return d; }; } } expect: { function f(n) { return function() { return a ? b : c ? d : n; }; } } } keep_fnames: { options = { conditionals: true, if_return: true, unsafe: true } mangle = { keep_fnames: true } input: { function f(undefined) { return function() { function n(a) { return a * a; } if (a) return b; if (c) return d; }; } } expect: { function f(r) { return function() { function n(n) { return n * n; } return a ? b : c ? d : r; }; } } } UglifyJS2-2.8.29/test/compress/issue-1446.js000066400000000000000000000032701312030606600202650ustar00rootroot00000000000000typeof_eq_undefined: { options = { comparisons: true } input: { var a = typeof b != "undefined"; b = typeof a != "undefined"; var c = typeof d.e !== "undefined"; var f = "undefined" === typeof g; g = "undefined" === typeof f; var h = "undefined" == typeof i.j; } expect: { var a = "undefined" != typeof b; b = void 0 !== a; var c = void 0 !== d.e; var f = "undefined" == typeof g; g = void 0 === f; var h = void 0 === i.j; } } typeof_eq_undefined_ie8: { options = { comparisons: true, screw_ie8: false } input: { var a = typeof b != "undefined"; b = typeof a != "undefined"; var c = typeof d.e !== "undefined"; var f = "undefined" === typeof g; g = "undefined" === typeof f; var h = "undefined" == typeof i.j; } expect: { var a = "undefined" != typeof b; b = void 0 !== a; var c = "undefined" != typeof d.e; var f = "undefined" == typeof g; g = void 0 === f; var h = "undefined" == typeof i.j; } } undefined_redefined: { options = { comparisons: true } input: { function f(undefined) { var n = 1; return typeof n == "undefined"; } } expect_exact: "function f(undefined){var n=1;return void 0===n}" } undefined_redefined_mangle: { options = { comparisons: true } mangle = {} input: { function f(undefined) { var n = 1; return typeof n == "undefined"; } } expect_exact: "function f(n){var r=1;return void 0===r}" } UglifyJS2-2.8.29/test/compress/issue-1447.js000066400000000000000000000016671312030606600202760ustar00rootroot00000000000000else_with_empty_block: { options = {} input: { if (x) yes(); else { } } expect_exact: "if(x)yes();" } else_with_empty_statement: { options = {} input: { if (x) yes(); else ; } expect_exact: "if(x)yes();" } conditional_false_stray_else_in_loop: { options = { evaluate : true, comparisons : true, booleans : true, unused : true, loops : true, side_effects : true, dead_code : true, hoist_vars : true, join_vars : true, if_return : true, cascade : true, conditionals : false, } input: { for (var i = 1; i <= 4; ++i) { if (i <= 2) continue; console.log(i); } } expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);" expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-1569.js000066400000000000000000000005311312030606600202700ustar00rootroot00000000000000inner_reference: { options = { side_effects: true, } input: { !function f(a) { return a && f(a - 1) + a; }(42); !function g(a) { return a; }(42); } expect: { !function f(a) { return a && f(a - 1) + a; }(42); !void 0; } } UglifyJS2-2.8.29/test/compress/issue-1588.js000066400000000000000000000035741312030606600203030ustar00rootroot00000000000000screw_ie8: { options = { screw_ie8: true, } mangle = { screw_ie8: true, } input: { try { throw "foo"; } catch (x) { console.log(x); } } expect_exact: 'try{throw"foo"}catch(o){console.log(o)}' expect_stdout: [ "foo" ] } support_ie8: { options = { screw_ie8: false, } mangle = { screw_ie8: false, } input: { try { throw "foo"; } catch (x) { console.log(x); } } expect_exact: 'try{throw"foo"}catch(x){console.log(x)}' expect_stdout: "foo" } safe_undefined: { options = { conditionals: true, if_return: true, unsafe: false, } mangle = {} input: { var a, c; console.log(function(undefined) { return function() { if (a) return b; if (c) return d; }; }(1)()); } expect: { var a, c; console.log(function(n) { return function() { return a ? b : c ? d : void 0; }; }(1)()); } expect_stdout: true } unsafe_undefined: { options = { conditionals: true, if_return: true, unsafe: true, } mangle = {} input: { var a, c; console.log(function(undefined) { return function() { if (a) return b; if (c) return d; }; }()()); } expect: { var a, c; console.log(function(n) { return function() { return a ? b : c ? d : n; }; }()()); } expect_stdout: true } runtime_error: { input: { const a = 1; console.log(a++); } expect: { const a = 1; console.log(a++); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-1609.js000066400000000000000000000021301312030606600202600ustar00rootroot00000000000000chained_evaluation_1: { options = { collapse_vars: true, evaluate: true, reduce_vars: true, unused: true, } input: { (function() { var a = 1; (function() { var b = a, c; c = f(b); c.bar = b; })(); })(); } expect: { (function() { (function() { var c; c = f(1); c.bar = 1; })(); })(); } } chained_evaluation_2: { options = { collapse_vars: true, evaluate: true, reduce_vars: true, unused: true, } input: { (function() { var a = "long piece of string"; (function() { var b = a, c; c = f(b); c.bar = b; })(); })(); } expect: { (function() { (function() { var c, b = "long piece of string"; c = f(b); c.bar = b; })(); })(); } } UglifyJS2-2.8.29/test/compress/issue-1639.js000066400000000000000000000032131312030606600202660ustar00rootroot00000000000000 issue_1639_1: { options = { booleans: true, cascade: true, conditionals: true, evaluate: true, join_vars: true, loops: true, sequences: true, side_effects: true, } input: { var a = 100, b = 10; var L1 = 5; while (--L1 > 0) { if ((--b), false) { if (b) { var ignore = 0; } } } console.log(a, b); } expect: { for (var a = 100, b = 10, L1 = 5; --L1 > 0;) if (--b, !1) var ignore = 0; console.log(a, b); } expect_stdout: true } issue_1639_2: { options = { booleans: true, cascade: true, conditionals: true, evaluate: true, join_vars: true, sequences: true, side_effects: true, } input: { var a = 100, b = 10; function f19() { if (++a, false) if (a) if (++a); } f19(); console.log(a, b); } expect: { var a = 100, b = 10; function f19() { ++a, 1; } f19(), console.log(a, b); } expect_stdout: true } issue_1639_3: { options = { booleans: true, cascade: true, conditionals: true, evaluate: true, sequences: true, side_effects: true, } input: { var a = 100, b = 10; a++ && false && a ? 0 : 0; console.log(a, b); } expect: { var a = 100, b = 10; a++, console.log(a, b); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-1656.js000066400000000000000000000017771312030606600203020ustar00rootroot00000000000000f7: { options = { booleans: true, cascade: true, collapse_vars: true, comparisons: true, conditionals: true, dead_code: true, drop_debugger: true, evaluate: true, hoist_funs: true, if_return: true, join_vars: true, loops: true, negate_iife: true, passes: 3, properties: true, reduce_vars: true, sequences: true, side_effects: true, toplevel: true, unused: true, } beautify = { beautify: true, } input: { var a = 100, b = 10; function f22464() { var brake146670 = 5; while (((b = a) ? !a : ~a ? null : b += a) && --brake146670 > 0) { } } f22464(); console.log(a, b); } expect_exact: [ "var b = 10;", "", "!function() {", " for (;b = 100, !1; ) ;", "}(), console.log(100, b);", ] expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-1673.js000066400000000000000000000060561312030606600202740ustar00rootroot00000000000000side_effects_catch: { options = { reduce_vars: true, side_effects: true, unused: true, } input: { function f() { function g() { try { throw 0; } catch (e) { console.log("PASS"); } } g(); } f(); } expect: { function f() { (function() { try { throw 0; } catch (e) { console.log("PASS"); } })(); } f(); } expect_stdout: "PASS" } side_effects_else: { options = { reduce_vars: true, side_effects: true, unused: true, } input: { function f(x) { function g() { if (x); else console.log("PASS"); } g(); } f(0); } expect: { function f(x) { (function() { if (x); else console.log("PASS"); })(); } f(0); } expect_stdout: "PASS" } side_effects_finally: { options = { reduce_vars: true, side_effects: true, unused: true, } input: { function f() { function g() { try { x(); } catch (e) { } finally { console.log("PASS"); } } g(); } f(); } expect: { function f() { (function() { try { x(); } catch (e) { } finally { console.log("PASS"); } })(); } f(); } expect_stdout: "PASS" } side_effects_label: { options = { reduce_vars: true, side_effects: true, unused: true, } input: { function f(x) { function g() { L: { console.log("PASS"); break L; } } g(); } f(0); } expect: { function f(x) { (function() { L: { console.log("PASS"); break L; } })(); } f(0); } expect_stdout: "PASS" } side_effects_switch: { options = { reduce_vars: true, side_effects: true, unused: true, } input: { function f() { function g() { switch (0) { default: case console.log("PASS"): } } g(); } f(); } expect: { function f() { (function() { switch (0) { default: case console.log("PASS"): } })(); } f(); } expect_stdout: "PASS" } UglifyJS2-2.8.29/test/compress/issue-1704.js000066400000000000000000000156551312030606600202740ustar00rootroot00000000000000mangle_catch: { options = { screw_ie8: true, toplevel: false, } mangle = { screw_ie8: true, toplevel: false, } input: { var a = "FAIL"; try { throw 1; } catch (args) { a = "PASS"; } console.log(a); } expect_exact: 'var a="FAIL";try{throw 1}catch(o){a="PASS"}console.log(a);' expect_stdout: "PASS" } mangle_catch_ie8: { options = { screw_ie8: false, toplevel: false, } mangle = { screw_ie8: false, toplevel: false, } input: { var a = "FAIL"; try { throw 1; } catch (args) { a = "PASS"; } console.log(a); } expect_exact: 'var a="FAIL";try{throw 1}catch(args){a="PASS"}console.log(a);' expect_stdout: "PASS" } mangle_catch_var: { options = { screw_ie8: true, toplevel: false, } mangle = { screw_ie8: true, toplevel: false, } input: { var a = "FAIL"; try { throw 1; } catch (args) { var a = "PASS"; } console.log(a); } expect_exact: 'var a="FAIL";try{throw 1}catch(o){var a="PASS"}console.log(a);' expect_stdout: "PASS" } mangle_catch_var_ie8: { options = { screw_ie8: false, toplevel: false, } mangle = { screw_ie8: false, toplevel: false, } input: { var a = "FAIL"; try { throw 1; } catch (args) { var a = "PASS"; } console.log(a); } expect_exact: 'var a="FAIL";try{throw 1}catch(args){var a="PASS"}console.log(a);' expect_stdout: "PASS" } mangle_catch_toplevel: { options = { screw_ie8: true, toplevel: true, } mangle = { screw_ie8: true, toplevel: true, } input: { var a = "FAIL"; try { throw 1; } catch (args) { a = "PASS"; } console.log(a); } expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);' expect_stdout: "PASS" } mangle_catch_ie8_toplevel: { options = { screw_ie8: false, toplevel: true, } mangle = { screw_ie8: false, toplevel: true, } input: { var a = "FAIL"; try { throw 1; } catch (args) { a = "PASS"; } console.log(a); } expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);' expect_stdout: "PASS" } mangle_catch_var_toplevel: { options = { screw_ie8: true, toplevel: true, } mangle = { screw_ie8: true, toplevel: true, } input: { var a = "FAIL"; try { throw 1; } catch (args) { var a = "PASS"; } console.log(a); } expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);' expect_stdout: "PASS" } mangle_catch_var_ie8_toplevel: { options = { screw_ie8: false, toplevel: true, } mangle = { screw_ie8: false, toplevel: true, } input: { var a = "FAIL"; try { throw 1; } catch (args) { var a = "PASS"; } console.log(a); } expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);' expect_stdout: "PASS" } mangle_catch_redef_1: { options = { screw_ie8: true, toplevel: false, } mangle = { screw_ie8: true, toplevel: false, } input: { var a = "PASS"; try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);' expect_stdout: "PASS" } mangle_catch_redef_1_ie8: { options = { screw_ie8: false, toplevel: false, } mangle = { screw_ie8: false, toplevel: false, } input: { var a = "PASS"; try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);' expect_stdout: "PASS" } mangle_catch_redef_1_toplevel: { options = { screw_ie8: true, toplevel: true, } mangle = { screw_ie8: true, toplevel: true, } input: { var a = "PASS"; try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);' expect_stdout: "PASS" } mangle_catch_redef_1_ie8_toplevel: { options = { screw_ie8: false, toplevel: true, } mangle = { screw_ie8: false, toplevel: true, } input: { var a = "PASS"; try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);' expect_stdout: "PASS" } mangle_catch_redef_2: { options = { screw_ie8: true, toplevel: false, } mangle = { screw_ie8: true, toplevel: false, } input: { try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);' expect_stdout: "undefined" } mangle_catch_redef_2_ie8: { options = { screw_ie8: false, toplevel: false, } mangle = { screw_ie8: false, toplevel: false, } input: { try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);' expect_stdout: "undefined" } mangle_catch_redef_2_toplevel: { options = { screw_ie8: true, toplevel: true, } mangle = { screw_ie8: true, toplevel: true, } input: { try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);' expect_stdout: "undefined" } mangle_catch_redef_2_ie8_toplevel: { options = { screw_ie8: false, toplevel: true, } mangle = { screw_ie8: false, toplevel: true, } input: { try { throw "FAIL1"; } catch (a) { var a = "FAIL2"; } console.log(a); } expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);' expect_stdout: "undefined" } UglifyJS2-2.8.29/test/compress/issue-1733.js000066400000000000000000000042351312030606600202660ustar00rootroot00000000000000function_iife_catch: { mangle = { screw_ie8: true, } input: { function f(n) { !function() { try { throw 0; } catch (n) { var a = 1; console.log(n, a); } }(); } f(); } expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();" expect_stdout: "0 1" } function_iife_catch_ie8: { mangle = { screw_ie8: false, } input: { function f(n) { !function() { try { throw 0; } catch (n) { var a = 1; console.log(n, a); } }(); } f(); } expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();" expect_stdout: "0 1" } function_catch_catch: { mangle = { screw_ie8: true, } input: { var o = 0; function f() { try { throw 1; } catch (c) { try { throw 2; } catch (o) { var o = 3; console.log(o); } } console.log(o); } f(); } expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();" expect_stdout: [ "3", "undefined", ] } function_catch_catch_ie8: { mangle = { screw_ie8: false, } input: { var o = 0; function f() { try { throw 1; } catch (c) { try { throw 2; } catch (o) { var o = 3; console.log(o); } } console.log(o); } f(); } expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();" expect_stdout: [ "3", "undefined", ] } UglifyJS2-2.8.29/test/compress/issue-1750.js000066400000000000000000000016551312030606600202700ustar00rootroot00000000000000case_1: { options = { dead_code: true, evaluate: true, switches: true, } input: { var a = 0, b = 1; switch (true) { case a, true: default: b = 2; case true: } console.log(a, b); } expect: { var a = 0, b = 1; switch (true) { case a, true: b = 2; } console.log(a, b); } expect_stdout: "0 2" } case_2: { options = { dead_code: true, evaluate: true, switches: true, } input: { var a = 0, b = 1; switch (0) { default: b = 2; case a: a = 3; case 0: } console.log(a, b); } expect: { var a = 0, b = 1; switch (0) { case a: a = 3; } console.log(a, b); } expect_stdout: "3 1" } UglifyJS2-2.8.29/test/compress/issue-1770.js000066400000000000000000000117631312030606600202730ustar00rootroot00000000000000mangle_props: { mangle_props = {} input: { var obj = { undefined: 1, NaN: 2, Infinity: 3, "-Infinity": 4, null: 5, }; console.log( obj[void 0], obj[undefined], obj["undefined"], obj[0/0], obj[NaN], obj["NaN"], obj[1/0], obj[Infinity], obj["Infinity"], obj[-1/0], obj[-Infinity], obj["-Infinity"], obj[null], obj["null"] ); } expect: { var obj = { undefined: 1, NaN: 2, Infinity: 3, "-Infinity": 4, null: 5, }; console.log( obj[void 0], obj[void 0], obj["undefined"], obj[0/0], obj[NaN], obj["NaN"], obj[1/0], obj[1/0], obj["Infinity"], obj[-1/0], obj[-1/0], obj["-Infinity"], obj[null], obj["null"] ); } expect_stdout: "1 1 1 2 2 2 3 3 3 4 4 4 5 5" } numeric_literal: { beautify = { beautify: true, } mangle_props = {} input: { var obj = { 0: 0, "-0": 1, 42: 2, "42": 3, 0x25: 4, "0x25": 5, 1E42: 6, "1E42": 7, "1e+42": 8, }; console.log(obj[-0], obj[-""], obj["-0"]); console.log(obj[42], obj["42"]); console.log(obj[0x25], obj["0x25"], obj[37], obj["37"]); console.log(obj[1E42], obj["1E42"], obj["1e+42"]); } expect_exact: [ 'var obj = {', ' 0: 0,', ' "-0": 1,', ' 42: 2,', ' "42": 3,', ' 37: 4,', ' a: 5,', ' 1e42: 6,', ' b: 7,', ' "1e+42": 8', '};', '', 'console.log(obj[-0], obj[-""], obj["-0"]);', '', 'console.log(obj[42], obj["42"]);', '', 'console.log(obj[37], obj["a"], obj[37], obj["37"]);', '', 'console.log(obj[1e42], obj["b"], obj["1e+42"]);', ] expect_stdout: [ "0 0 1", "3 3", "4 5 4 4", "8 7 8", ] } identifier: { mangle_props = {} input: { var obj = { abstract: 1, boolean: 2, byte: 3, char: 4, class: 5, double: 6, enum: 7, export: 8, extends: 9, final: 10, float: 11, goto: 12, implements: 13, import: 14, int: 15, interface: 16, let: 17, long: 18, native: 19, package: 20, private: 21, protected: 22, public: 23, short: 24, static: 25, super: 26, synchronized: 27, this: 28, throws: 29, transient: 30, volatile: 31, yield: 32, false: 33, null: 34, true: 35, break: 36, case: 37, catch: 38, const: 39, continue: 40, debugger: 41, default: 42, delete: 43, do: 44, else: 45, finally: 46, for: 47, function: 48, if: 49, in: 50, instanceof: 51, new: 52, return: 53, switch: 54, throw: 55, try: 56, typeof: 57, var: 58, void: 59, while: 60, with: 61, }; } expect: { var obj = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20, u: 21, v: 22, w: 23, x: 24, y: 25, z: 26, A: 27, B: 28, C: 29, D: 30, F: 31, G: 32, false: 33, null: 34, true: 35, H: 36, I: 37, J: 38, K: 39, L: 40, M: 41, N: 42, O: 43, P: 44, Q: 45, R: 46, S: 47, T: 48, U: 49, V: 50, W: 51, X: 52, Y: 53, Z: 54, $: 55, _: 56, aa: 57, ba: 58, ca: 59, da: 60, ea: 61, }; } } UglifyJS2-2.8.29/test/compress/issue-1787.js000066400000000000000000000005351312030606600202760ustar00rootroot00000000000000unary_prefix: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { console.log(function() { var x = -(2 / 3); return x; }()); } expect: { console.log(function() { return -2 / 3; }()); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-1833.js000066400000000000000000000044171312030606600202710ustar00rootroot00000000000000iife_for: { options = { negate_iife: true, reduce_vars: true, toplevel: true, unused: true, } input: { function f() { function g() { L: for (;;) break L; } g(); } f(); } expect: { !function() { !function() { L: for (;;) break L; }(); }(); } } iife_for_in: { options = { negate_iife: true, reduce_vars: true, toplevel: true, unused: true, } input: { function f() { function g() { L: for (var a in x) break L; } g(); } f(); } expect: { !function() { !function() { L: for (var a in x) break L; }(); }(); } } iife_do: { options = { negate_iife: true, reduce_vars: true, toplevel: true, unused: true, } input: { function f() { function g() { L: do { break L; } while (1); } g(); } f(); } expect: { !function() { !function() { L: do { break L; } while (1); }(); }(); } } iife_while: { options = { negate_iife: true, reduce_vars: true, toplevel: true, unused: true, } input: { function f() { function g() { L: while (1) break L; } g(); } f(); } expect: { !function() { !function() { L: while (1) break L; }(); }(); } } label_do: { options = { evaluate: true, loops: true, } input: { L: do { continue L; } while (0); } expect: { L: do { continue L; } while (0); } } label_while: { options = { evaluate: true, dead_code: true, loops: true, } input: { function f() { L: while (0) continue L; } } expect_exact: "function f(){L:;}" } UglifyJS2-2.8.29/test/compress/issue-1943.js000066400000000000000000000005721312030606600202710ustar00rootroot00000000000000operator: { input: { a. //comment typeof } expect_exact: "a.typeof;" } name: { input: { a. //comment b } expect_exact: "a.b;" } keyword: { input: { a. //comment default } expect_exact: "a.default;" } atom: { input: { a. //comment true } expect_exact: "a.true;" } UglifyJS2-2.8.29/test/compress/issue-208.js000066400000000000000000000026731312030606600202060ustar00rootroot00000000000000do_not_update_lhs: { options = { global_defs: { DEBUG: 0 } } input: { DEBUG++; DEBUG += 1; DEBUG = 1; } expect: { DEBUG++; DEBUG += 1; DEBUG = 1; } } do_update_rhs: { options = { global_defs: { DEBUG: 0 } } input: { MY_DEBUG = DEBUG; MY_DEBUG += DEBUG; } expect: { MY_DEBUG = 0; MY_DEBUG += 0; } } mixed: { options = { evaluate: true, global_defs: { DEBUG: 0, ENV: 1, FOO: 2, } } input: { const ENV = 3; var FOO = 4; f(ENV * 10); --FOO; DEBUG = 1; DEBUG++; DEBUG += 1; f(DEBUG); x = DEBUG; } expect: { const ENV = 3; var FOO = 4; f(10); --FOO; DEBUG = 1; DEBUG++; DEBUG += 1; f(0); x = 0; } expect_warnings: [ 'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,14]', 'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]', 'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]', 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]', 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:46,8]', 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:47,8]', ] } UglifyJS2-2.8.29/test/compress/issue-22.js000066400000000000000000000005201312030606600201050ustar00rootroot00000000000000return_with_no_value_in_if_body: { options = { conditionals: true }; input: { function foo(bar) { if (bar) { return; } else { return 1; } } } expect: { function foo (bar) { return bar ? void 0 : 1; } } } UglifyJS2-2.8.29/test/compress/issue-267.js000066400000000000000000000003061312030606600202020ustar00rootroot00000000000000issue_267: { options = { comparisons: true }; input: { x = a % b / b * c * 2; x = a % b * 2 } expect: { x = a % b / b * c * 2; x = a % b * 2; } } UglifyJS2-2.8.29/test/compress/issue-269.js000066400000000000000000000014401312030606600202040ustar00rootroot00000000000000issue_269_1: { options = {unsafe: true}; input: { f( String(x), Number(x), Boolean(x), String(), Number(), Boolean() ); } expect: { f( x + '', +x, !!x, '', 0, false ); } } issue_269_dangers: { options = {unsafe: true}; input: { f( String(x, x), Number(x, x), Boolean(x, x) ); } expect: { f(String(x, x), Number(x, x), Boolean(x, x)); } } issue_269_in_scope: { options = {unsafe: true}; input: { var String, Number, Boolean; f( String(x), Number(x, x), Boolean(x) ); } expect: { var String, Number, Boolean; f(String(x), Number(x, x), Boolean(x)); } } strings_concat: { options = {unsafe: true}; input: { f( String(x + 'str'), String('str' + x) ); } expect: { f( x + 'str', 'str' + x ); } } UglifyJS2-2.8.29/test/compress/issue-368.js000066400000000000000000000024641312030606600202130ustar00rootroot00000000000000collapse: { options = { cascade: true, sequences: true, side_effects: true, unused: true, } input: { function f1() { var a; a = typeof b === 'function' ? b() : b; return a !== undefined && c(); } function f2(b) { var a; b = c(); a = typeof b === 'function' ? b() : b; return 'stirng' == typeof a && d(); } function f3(c) { var a; a = b(a / 2); if (a < 0) { a++; ++c; return c / 2; } } function f4(c) { var a; a = b(a / 2); if (a < 0) { a++; c++; return c / 2; } } } expect: { function f1() { return void 0 !== ('function' === typeof b ? b() : b) && c(); } function f2(b) { return b = c(), 'stirng' == typeof ('function' === typeof b ? b() : b) && d(); } function f3(c) { var a; if ((a = b(a / 2)) < 0) return a++, ++c / 2; } function f4(c) { var a; if ((a = b(a / 2)) < 0) return a++, ++c / 2; } } } UglifyJS2-2.8.29/test/compress/issue-44.js000066400000000000000000000011311312030606600201100ustar00rootroot00000000000000issue_44_valid_ast_1: { options = { unused: true }; input: { function a(b) { for (var i = 0, e = b.qoo(); ; i++) {} } } expect: { function a(b) { var i = 0; for (b.qoo(); ; i++); } } } issue_44_valid_ast_2: { options = { unused: true }; input: { function a(b) { if (foo) for (var i = 0, e = b.qoo(); ; i++) {} } } expect: { function a(b) { if (foo) { var i = 0; for (b.qoo(); ; i++); } } } } UglifyJS2-2.8.29/test/compress/issue-59.js000066400000000000000000000010471312030606600201240ustar00rootroot00000000000000keep_continue: { options = { dead_code: true, evaluate: true }; input: { while (a) { if (b) { switch (true) { case c(): d(); } continue; } f(); } } expect: { while (a) { if (b) { switch (true) { case c(): d(); } continue; } f(); } } } UglifyJS2-2.8.29/test/compress/issue-597.js000066400000000000000000000062531312030606600202170ustar00rootroot00000000000000NaN_and_Infinity_must_have_parens: { options = {}; input: { Infinity.toString(); NaN.toString(); } expect: { (1/0).toString(); NaN.toString(); } } NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: { options = {}; input: { var Infinity, NaN; Infinity.toString(); NaN.toString(); } expect: { var Infinity, NaN; Infinity.toString(); NaN.toString(); } } NaN_and_Infinity_must_have_parens_evaluate: { options = { evaluate: true, } input: { (123456789 / 0).toString(); (+"foo").toString(); } expect: { (1/0).toString(); NaN.toString(); } } NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined_evaluate: { options = { evaluate: true, } input: { var Infinity, NaN; (123456789 / 0).toString(); (+"foo").toString(); } expect: { var Infinity, NaN; (1/0).toString(); (0/0).toString(); } } beautify_off_1: { options = { evaluate: true, } beautify = { beautify: false, } input: { var NaN; console.log( null, undefined, Infinity, NaN, Infinity * undefined, Infinity.toString(), NaN.toString(), (Infinity * undefined).toString() ); } expect_exact: "var NaN;console.log(null,void 0,1/0,NaN,0/0,(1/0).toString(),NaN.toString(),(0/0).toString());" expect_stdout: true } beautify_off_2: { options = { evaluate: true, } beautify = { beautify: false, } input: { console.log( null.toString(), undefined.toString() ); } expect_exact: "console.log(null.toString(),(void 0).toString());" } beautify_on_1: { options = { evaluate: true, } beautify = { beautify: true, } input: { var NaN; console.log( null, undefined, Infinity, NaN, Infinity * undefined, Infinity.toString(), NaN.toString(), (Infinity * undefined).toString() ); } expect_exact: [ "var NaN;", "", "console.log(null, void 0, 1 / 0, NaN, 0 / 0, (1 / 0).toString(), NaN.toString(), (0 / 0).toString());", ] expect_stdout: true } beautify_on_2: { options = { evaluate: true, } beautify = { beautify: true, } input: { console.log( null.toString(), undefined.toString() ); } expect_exact: "console.log(null.toString(), (void 0).toString());" } issue_1724: { input: { var a = 0; ++a % Infinity | Infinity ? a++ : 0; console.log(a); } expect_exact: "var a=0;++a%(1/0)|1/0?a++:0;console.log(a);" expect_stdout: "2" } issue_1725: { input: { ([].length === 0) % Infinity ? console.log("PASS") : console.log("FAIL"); } expect_exact: '(0===[].length)%(1/0)?console.log("PASS"):console.log("FAIL");' expect_stdout: "PASS" } UglifyJS2-2.8.29/test/compress/issue-611.js000066400000000000000000000004731312030606600202000ustar00rootroot00000000000000issue_611: { options = { sequences: true, side_effects: true }; input: { define(function() { function fn() {} if (fn()) { fn(); return void 0; } }); } expect: { define(function() { function fn(){} if (fn()) return void fn(); }); } } UglifyJS2-2.8.29/test/compress/issue-637.js000066400000000000000000000006241312030606600202060ustar00rootroot00000000000000wrongly_optimized: { options = { conditionals: true, booleans: true, evaluate: true }; input: { function func() { foo(); } if (func() || true) { bar(); } } expect: { function func() { foo(); } // TODO: optimize to `func(), bar()` (func(), 0) || bar(); } } UglifyJS2-2.8.29/test/compress/issue-640.js000066400000000000000000000150671312030606600202070ustar00rootroot00000000000000cond_5: { options = { conditionals: true, expression: true, } input: { if (some_condition()) { if (some_other_condition()) { do_something(); } else { alternate(); } } else { alternate(); } if (some_condition()) { if (some_other_condition()) { do_something(); } } } expect: { some_condition() && some_other_condition() ? do_something() : alternate(); if (some_condition() && some_other_condition()) do_something(); } } dead_code_const_annotation_regex: { options = { booleans : true, conditionals : true, dead_code : true, evaluate : true, expression : true, loops : true, } input: { var unused; // @constraint this shouldn't be a constant var CONST_FOO_ANN = false; if (CONST_FOO_ANN) { console.log("reachable"); } } expect: { var unused; var CONST_FOO_ANN = !1; if (CONST_FOO_ANN) console.log('reachable'); } expect_stdout: true } drop_console_2: { options = { drop_console: true, expression: true, } input: { console.log('foo'); console.log.apply(console, arguments); } expect: { // with regular compression these will be stripped out as well void 0; void 0; } } drop_value: { options = { expression: true, side_effects: true, } input: { (1, [2, foo()], 3, {a:1, b:bar()}); } expect: { foo(), {a:1, b:bar()}; } } wrongly_optimized: { options = { conditionals: true, booleans: true, evaluate: true, expression: true, } input: { function func() { foo(); } if (func() || true) { bar(); } } expect: { function func() { foo(); } // TODO: optimize to `func(), bar()` if (func(), !0) bar(); } } negate_iife_1: { options = { expression: true, negate_iife: true, } input: { (function(){ stuff() })(); } expect: { (function(){ stuff() })(); } } negate_iife_3: { options = { conditionals: true, expression: true, negate_iife: true, } input: { (function(){ return t })() ? console.log(true) : console.log(false); } expect: { (function(){ return t })() ? console.log(true) : console.log(false); } } negate_iife_3_off: { options = { conditionals: true, expression: true, negate_iife: false, } input: { (function(){ return t })() ? console.log(true) : console.log(false); } expect: { (function(){ return t })() ? console.log(true) : console.log(false); } } negate_iife_4: { options = { conditionals: true, expression: true, negate_iife: true, sequences: true, } input: { (function(){ return t })() ? console.log(true) : console.log(false); (function(){ console.log("something"); })(); } expect: { (function(){ return t })() ? console.log(true) : console.log(false), function(){ console.log("something"); }(); } } negate_iife_5: { options = { conditionals: true, expression: true, negate_iife: true, sequences: true, } input: { if ((function(){ return t })()) { foo(true); } else { bar(false); } (function(){ console.log("something"); })(); } expect: { (function(){ return t })() ? foo(true) : bar(false), function(){ console.log("something"); }(); } } negate_iife_5_off: { options = { conditionals: true, expression: true, negate_iife: false, sequences: true, }; input: { if ((function(){ return t })()) { foo(true); } else { bar(false); } (function(){ console.log("something"); })(); } expect: { (function(){ return t })() ? foo(true) : bar(false), function(){ console.log("something"); }(); } } issue_1254_negate_iife_true: { options = { expression: true, negate_iife: true, } input: { (function() { return function() { console.log('test') }; })()(); } expect_exact: '(function(){return function(){console.log("test")}})()();' expect_stdout: true } issue_1254_negate_iife_nested: { options = { expression: true, negate_iife: true, } input: { (function() { return function() { console.log('test') }; })()()()()(); } expect_exact: '(function(){return function(){console.log("test")}})()()()()();' expect_stdout: true } conditional: { options = { expression: true, pure_funcs: [ "pure" ], side_effects: true, } input: { pure(1 | a() ? 2 & b() : 7 ^ c()); pure(1 | a() ? 2 & b() : 5); pure(1 | a() ? 4 : 7 ^ c()); pure(1 | a() ? 4 : 5); pure(3 ? 2 & b() : 7 ^ c()); pure(3 ? 2 & b() : 5); pure(3 ? 4 : 7 ^ c()); pure(3 ? 4 : 5); } expect: { 1 | a() ? b() : c(); 1 | a() && b(); 1 | a() || c(); a(); 3 ? b() : c(); 3 && b(); 3 || c(); pure(3 ? 4 : 5); } } limit_1: { options = { expression: true, sequences: 3, } input: { a; b; c; d; e; f; g; h; i; j; k; } expect: { // Turned into a single return statement // so it can no longer be split into lines a,b,c,d,e,f,g,h,i,j,k; } } iife: { options = { expression: true, sequences: true, } input: { x = 42; (function a() {})(); !function b() {}(); ~function c() {}(); +function d() {}(); -function e() {}(); void function f() {}(); typeof function g() {}(); } expect: { x = 42, function a() {}(), function b() {}(), function c() {}(), function d() {}(), function e() {}(), function f() {}(), typeof function g() {}(); } } UglifyJS2-2.8.29/test/compress/issue-747.js000066400000000000000000000011551312030606600202100ustar00rootroot00000000000000dont_reuse_prop: { mangle_props = { regex: /asd/ }; input: { var obj = {}; obj.a = 123; obj.asd = 256; console.log(obj.a); } expect: { var obj = {}; obj.a = 123; obj.b = 256; console.log(obj.a); } } unmangleable_props_should_always_be_reserved: { mangle_props = { regex: /asd/ }; input: { var obj = {}; obj.asd = 256; obj.a = 123; console.log(obj.a); } expect: { var obj = {}; obj.b = 256; obj.a = 123; console.log(obj.a); } }UglifyJS2-2.8.29/test/compress/issue-751.js000066400000000000000000000010551312030606600202020ustar00rootroot00000000000000negate_booleans_1: { options = { comparisons: true }; input: { var a = !a || !b || !c || !d || !e || !f; } expect: { var a = !(a && b && c && d && e && f); } } negate_booleans_2: { options = { comparisons: true }; input: { var match = !x && // should not touch this one (!z || c) && (!k || d) && the_stuff(); } expect: { var match = !x && (!z || c) && (!k || d) && the_stuff(); } } UglifyJS2-2.8.29/test/compress/issue-782.js000066400000000000000000000010521312030606600202030ustar00rootroot00000000000000remove_redundant_sequence_items: { options = { side_effects: true }; input: { (0, 1, eval)(); (0, 1, logThis)(); (0, 1, _decorators.logThis)(); } expect: { (0, eval)(); logThis(); (0, _decorators.logThis)(); } } dont_remove_this_binding_sequence: { options = { side_effects: true }; input: { (0, eval)(); (0, logThis)(); (0, _decorators.logThis)(); } expect: { (0, eval)(); logThis(); (0, _decorators.logThis)(); } } UglifyJS2-2.8.29/test/compress/issue-892.js000066400000000000000000000016421312030606600202120ustar00rootroot00000000000000dont_mangle_arguments: { mangle = { }; options = { sequences : true, properties : true, dead_code : true, drop_debugger : true, conditionals : true, comparisons : true, evaluate : true, booleans : true, loops : true, unused : true, hoist_funs : true, keep_fargs : true, keep_fnames : false, hoist_vars : true, if_return : true, join_vars : true, cascade : true, side_effects : true, negate_iife : false }; input: { (function(){ var arguments = arguments, not_arguments = 9; console.log(not_arguments, arguments); })(5,6,7); } expect_exact: "(function(){var arguments=arguments,o=9;console.log(o,arguments)})(5,6,7);" expect_stdout: true } UglifyJS2-2.8.29/test/compress/issue-913.js000066400000000000000000000005651312030606600202070ustar00rootroot00000000000000keep_var_for_in: { options = { hoist_vars: true, unused: true }; input: { (function(obj){ var foo = 5; for (var i in obj) return foo; })(); } expect: { (function(obj){ var i, foo = 5; for (i in obj) return foo; })(); } } UglifyJS2-2.8.29/test/compress/issue-973.js000066400000000000000000000034541312030606600202150ustar00rootroot00000000000000this_binding_conditionals: { options = { conditionals: true, evaluate : true }; input: { (1 && a)(); (0 || a)(); (0 || 1 && a)(); (1 ? a : 0)(); (1 && a.b)(); (0 || a.b)(); (0 || 1 && a.b)(); (1 ? a.b : 0)(); (1 && a[b])(); (0 || a[b])(); (0 || 1 && a[b])(); (1 ? a[b] : 0)(); (1 && eval)(); (0 || eval)(); (0 || 1 && eval)(); (1 ? eval : 0)(); } expect: { a(); a(); a(); a(); (0, a.b)(); (0, a.b)(); (0, a.b)(); (0, a.b)(); (0, a[b])(); (0, a[b])(); (0, a[b])(); (0, a[b])(); (0, eval)(); (0, eval)(); (0, eval)(); (0, eval)(); } } this_binding_collapse_vars: { options = { collapse_vars: true, toplevel: true, }; input: { var c = a; c(); var d = a.b; d(); var e = eval; e(); } expect: { a(); (0, a.b)(); (0, eval)(); } } this_binding_side_effects: { options = { side_effects : true }; input: { (function (foo) { (0, foo)(); (0, foo.bar)(); (0, eval)('console.log(foo);'); }()); (function (foo) { var eval = console; (0, foo)(); (0, foo.bar)(); (0, eval)('console.log(foo);'); }()); } expect: { (function (foo) { foo(); (0, foo.bar)(); (0, eval)('console.log(foo);'); }()); (function (foo) { var eval = console; foo(); (0, foo.bar)(); (0, eval)('console.log(foo);'); }()); } }UglifyJS2-2.8.29/test/compress/issue-976.js000066400000000000000000000051071312030606600202150ustar00rootroot00000000000000eval_collapse_vars: { options = { collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true }; input: { function f1() { var e = 7; var s = "abcdef"; var i = 2; var eval = console.log.bind(console); var x = s.charAt(i++); var y = s.charAt(i++); var z = s.charAt(i++); eval(x, y, z, e); } function p1() { var a = foo(), b = bar(), eval = baz(); return a + b + eval; } function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); } (function f2(eval) { var a = 2; console.log(a - 5); eval("console.log(a);"); })(eval); } expect: { function f1() { var e = 7, s = "abcdef", i = 2, eval = console.log.bind(console), x = s.charAt(i++), y = s.charAt(i++), z = s.charAt(i++); eval(x, y, z, e); } function p1() { return foo() + bar() + baz(); } function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); } (function f2(eval) { var a = 2; console.log(a - 5); eval("console.log(a);"); })(eval); } expect_stdout: true } eval_unused: { options = { unused: true, keep_fargs: false }; input: { function f1(a, eval, c, d, e) { return a('c') + eval; } function f2(a, b, c, d, e) { return a + eval('c'); } function f3(a, eval, c, d, e) { return a + eval('c'); } } expect: { function f1(a, eval) { return a('c') + eval; } function f2(a, b, c, d, e) { return a + eval('c'); } function f3(a, eval, c, d, e) { return a + eval('c'); } } } eval_mangle: { mangle = { }; input: { function f1(a, eval, c, d, e) { return a('c') + eval; } function f2(a, b, c, d, e) { return a + eval('c'); } function f3(a, eval, c, d, e) { return a + eval('c'); } } expect_exact: 'function f1(n,c,e,a,f){return n("c")+c}function f2(a,b,c,d,e){return a+eval("c")}function f3(a,eval,c,d,e){return a+eval("c")}' } UglifyJS2-2.8.29/test/compress/issue-979.js000066400000000000000000000040551312030606600202210ustar00rootroot00000000000000issue979_reported: { options = { sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f1() { if (a == 1 || b == 2) { foo(); } } function f2() { if (!(a == 1 || b == 2)) { } else { foo(); } } } expect: { function f1() { 1!=a&&2!=b||foo(); } function f2() { 1!=a&&2!=b||foo(); } } } issue979_test_negated_is_best: { options = { sequences:true, properties:true, dead_code:true, conditionals:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true } input: { function f3() { if (a == 1 | b == 2) { foo(); } } function f4() { if (!(a == 1 | b == 2)) { } else { foo(); } } function f5() { if (a == 1 && b == 2) { foo(); } } function f6() { if (!(a == 1 && b == 2)) { } else { foo(); } } function f7() { if (a == 1 || b == 2) { foo(); } else { return bar(); } } } expect: { function f3() { 1==a|2==b&&foo(); } function f4() { 1==a|2==b&&foo(); } function f5() { 1==a&&2==b&&foo(); } function f6() { 1!=a||2!=b||foo(); } function f7() { if(1!=a&&2!=b)return bar();foo() } } } UglifyJS2-2.8.29/test/compress/labels.js000066400000000000000000000061501312030606600200030ustar00rootroot00000000000000labels_1: { options = { if_return: true, conditionals: true, dead_code: true }; input: { out: { if (foo) break out; console.log("bar"); } }; expect: { foo || console.log("bar"); } expect_stdout: true } labels_2: { options = { if_return: true, conditionals: true, dead_code: true }; input: { out: { if (foo) print("stuff"); else break out; console.log("here"); } }; expect: { if (foo) { print("stuff"); console.log("here"); } } } labels_3: { options = { if_return: true, conditionals: true, dead_code: true }; input: { for (var i = 0; i < 5; ++i) { if (i < 3) continue; console.log(i); } }; expect: { for (var i = 0; i < 5; ++i) i < 3 || console.log(i); } expect_stdout: true } labels_4: { options = { if_return: true, conditionals: true, dead_code: true }; input: { out: for (var i = 0; i < 5; ++i) { if (i < 3) continue out; console.log(i); } }; expect: { for (var i = 0; i < 5; ++i) i < 3 || console.log(i); } expect_stdout: true } labels_5: { options = { if_return: true, conditionals: true, dead_code: true }; // should keep the break-s in the following input: { while (foo) { if (bar) break; console.log("foo"); } out: while (foo) { if (bar) break out; console.log("foo"); } }; expect: { while (foo) { if (bar) break; console.log("foo"); } out: while (foo) { if (bar) break out; console.log("foo"); } } } labels_6: { input: { out: break out; }; expect: {} } labels_7: { options = { if_return: true, conditionals: true, dead_code: true }; input: { while (foo) { x(); y(); continue; } }; expect: { while (foo) { x(); y(); } } } labels_8: { options = { if_return: true, conditionals: true, dead_code: true }; input: { while (foo) { x(); y(); break; } }; expect: { while (foo) { x(); y(); break; } } } labels_9: { options = { if_return: true, conditionals: true, dead_code: true }; input: { out: while (foo) { x(); y(); continue out; z(); k(); } }; expect: { while (foo) { x(); y(); } } } labels_10: { options = { if_return: true, conditionals: true, dead_code: true }; input: { out: while (foo) { x(); y(); break out; z(); k(); } }; expect: { out: while (foo) { x(); y(); break out; } } } UglifyJS2-2.8.29/test/compress/loops.js000066400000000000000000000211201312030606600176670ustar00rootroot00000000000000while_becomes_for: { options = { loops: true }; input: { while (foo()) bar(); } expect: { for (; foo(); ) bar(); } } drop_if_break_1: { options = { loops: true }; input: { for (;;) if (foo()) break; } expect: { for (; !foo();); } } drop_if_break_2: { options = { loops: true }; input: { for (;bar();) if (foo()) break; } expect: { for (; bar() && !foo();); } } drop_if_break_3: { options = { loops: true }; input: { for (;bar();) { if (foo()) break; stuff1(); stuff2(); } } expect: { for (; bar() && !foo();) { stuff1(); stuff2(); } } } drop_if_break_4: { options = { loops: true, sequences: true }; input: { for (;bar();) { x(); y(); if (foo()) break; z(); k(); } } expect: { for (; bar() && (x(), y(), !foo());) z(), k(); } } drop_if_else_break_1: { options = { loops: true }; input: { for (;;) if (foo()) bar(); else break; } expect: { for (; foo(); ) bar(); } } drop_if_else_break_2: { options = { loops: true }; input: { for (;bar();) { if (foo()) baz(); else break; } } expect: { for (; bar() && foo();) baz(); } } drop_if_else_break_3: { options = { loops: true }; input: { for (;bar();) { if (foo()) baz(); else break; stuff1(); stuff2(); } } expect: { for (; bar() && foo();) { baz(); stuff1(); stuff2(); } } } drop_if_else_break_4: { options = { loops: true, sequences: true }; input: { for (;bar();) { x(); y(); if (foo()) baz(); else break; z(); k(); } } expect: { for (; bar() && (x(), y(), foo());) baz(), z(), k(); } } parse_do_while_with_semicolon: { options = { loops: false }; input: { do { x(); } while (false);y() } expect: { do x(); while (false);y(); } } parse_do_while_without_semicolon: { options = { loops: false }; input: { do { x(); } while (false)y() } expect: { do x(); while (false);y(); } } keep_collapse_const_in_own_block_scope: { options = { join_vars: true, loops: true } input: { var i=2; const c=5; while(i--) console.log(i); console.log(c); } expect: { var i=2; const c=5; for(;i--;) console.log(i); console.log(c); } expect_stdout: true } keep_collapse_const_in_own_block_scope_2: { options = { join_vars: true, loops: true } input: { const c=5; var i=2; // Moves to loop, while it did not in previous test while(i--) console.log(i); console.log(c); } expect: { const c=5; for(var i=2;i--;) console.log(i); console.log(c); } expect_stdout: true } evaluate: { options = { loops: true, dead_code: true, evaluate: true, }; input: { while (true) { a(); } while (false) { b(); } do { c(); } while (true); do { d(); } while (false); } expect: { for(;;) a(); for(;;) c(); d(); } } issue_1532: { options = { evaluate: true, loops: true, } input: { function f(x, y) { do { if (x) break; foo(); } while (false); } } expect: { function f(x, y) { do { if (x) break; foo(); } while (false); } } } issue_186: { beautify = { beautify: false, screw_ie8: true, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: 'var x=3;if(foo())do{do{alert(x)}while(--x)}while(x);else bar();' } issue_186_ie8: { beautify = { beautify: false, screw_ie8: false, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else bar();' } issue_186_beautify: { beautify = { beautify: true, screw_ie8: true, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: [ 'var x = 3;', '', 'if (foo()) do {', ' do {', ' alert(x);', ' } while (--x);', '} while (x); else bar();', ] } issue_186_beautify_ie8: { beautify = { beautify: true, screw_ie8: false, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: [ 'var x = 3;', '', 'if (foo()) {', ' do {', ' do {', ' alert(x);', ' } while (--x);', ' } while (x);', '} else bar();', ] } issue_186_bracketize: { beautify = { beautify: false, bracketize: true, screw_ie8: true, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}' } issue_186_bracketize_ie8: { beautify = { beautify: false, bracketize: true, screw_ie8: false, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}' } issue_186_beautify_bracketize: { beautify = { beautify: true, bracketize: true, screw_ie8: true, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: [ 'var x = 3;', '', 'if (foo()) {', ' do {', ' do {', ' alert(x);', ' } while (--x);', ' } while (x);', '} else {', ' bar();', '}', ] } issue_186_beautify_bracketize_ie8: { beautify = { beautify: true, bracketize: true, screw_ie8: false, } input: { var x = 3; if (foo()) do do alert(x); while (--x); while (x); else bar(); } expect_exact: [ 'var x = 3;', '', 'if (foo()) {', ' do {', ' do {', ' alert(x);', ' } while (--x);', ' } while (x);', '} else {', ' bar();', '}', ] } issue_1648: { options = { join_vars: true, loops: true, passes: 2, sequences: true, unused: true, } input: { function f() { x(); var b = 1; while (1); } } expect_exact: "function f(){for(x();1;);}" } do_switch: { options = { evaluate: true, loops: true, } input: { do { switch (a) { case b: continue; } } while (false); } expect: { do { switch (a) { case b: continue; } } while (false); } } UglifyJS2-2.8.29/test/compress/max_line_len.js000066400000000000000000000012441312030606600211720ustar00rootroot00000000000000too_short: { beautify = { max_line_len: 10, } input: { function f(a) { return { c: 42, d: a(), e: "foo"}; } } expect_exact: [ 'function f(a){', 'return{', 'c:42,', 'd:a(),', 'e:"foo"}}', ] expect_warnings: [ "WARN: Output exceeds 10 characters" ] } just_enough: { beautify = { max_line_len: 14, } input: { function f(a) { return { c: 42, d: a(), e: "foo"}; } } expect_exact: [ 'function f(a){', 'return{c:42,', 'd:a(),e:"foo"}', '}', ] expect_warnings: [ ] } UglifyJS2-2.8.29/test/compress/negate-iife.js000066400000000000000000000210751312030606600207210ustar00rootroot00000000000000negate_iife_1: { options = { negate_iife: true }; input: { (function(){ stuff() })(); } expect: { !function(){ stuff() }(); } } negate_iife_1_off: { options = { negate_iife: false, }; input: { (function(){ stuff() })(); } expect_exact: '(function(){stuff()})();' } negate_iife_2: { options = { negate_iife: true }; input: { (function(){ return {} })().x = 10; // should not transform this one } expect: { (function(){ return {} })().x = 10; } } negate_iife_2_side_effects: { options = { negate_iife: true, side_effects: true, } input: { (function(){ return {} })().x = 10; // should not transform this one } expect: { (function(){ return {} })().x = 10; } } negate_iife_3: { options = { negate_iife: true, conditionals: true }; input: { (function(){ return t })() ? console.log(true) : console.log(false); } expect: { !function(){ return t }() ? console.log(false) : console.log(true); } } negate_iife_3_evaluate: { options = { conditionals: true, evaluate: true, negate_iife: true, } input: { (function(){ return true })() ? console.log(true) : console.log(false); } expect: { console.log(true); } expect_stdout: true } negate_iife_3_side_effects: { options = { conditionals: true, negate_iife: true, side_effects: true, } input: { (function(){ return t })() ? console.log(true) : console.log(false); } expect: { !function(){ return t }() ? console.log(false) : console.log(true); } } negate_iife_3_off: { options = { negate_iife: false, conditionals: true, }; input: { (function(){ return t })() ? console.log(true) : console.log(false); } expect: { !function(){ return t }() ? console.log(false) : console.log(true); } } negate_iife_3_off_evaluate: { options = { conditionals: true, evaluate: true, negate_iife: false, } input: { (function(){ return true })() ? console.log(true) : console.log(false); } expect: { console.log(true); } expect_stdout: true } negate_iife_4: { options = { negate_iife: true, conditionals: true, sequences: true }; input: { (function(){ return t })() ? console.log(true) : console.log(false); (function(){ console.log("something"); })(); } expect: { !function(){ return t }() ? console.log(false) : console.log(true), function(){ console.log("something"); }(); } } sequence_off: { options = { negate_iife: false, conditionals: true, sequences: true, passes: 2, }; input: { function f() { (function(){ return t })() ? console.log(true) : console.log(false); (function(){ console.log("something"); })(); } function g() { (function(){ console.log("something"); })(); (function(){ return t })() ? console.log(true) : console.log(false); } } expect: { function f() { !function(){ return t }() ? console.log(false) : console.log(true), function(){ console.log("something"); }(); } function g() { (function(){ console.log("something"); })(), function(){ return t }() ? console.log(true) : console.log(false); } } } negate_iife_5: { options = { negate_iife: true, sequences: true, conditionals: true, }; input: { if ((function(){ return t })()) { foo(true); } else { bar(false); } (function(){ console.log("something"); })(); } expect: { !function(){ return t }() ? bar(false) : foo(true), function(){ console.log("something"); }(); } } negate_iife_5_off: { options = { negate_iife: false, sequences: true, conditionals: true, }; input: { if ((function(){ return t })()) { foo(true); } else { bar(false); } (function(){ console.log("something"); })(); } expect: { !function(){ return t }() ? bar(false) : foo(true), function(){ console.log("something"); }(); } } negate_iife_nested: { options = { negate_iife: true, sequences: true, conditionals: true, }; input: { function Foo(f) { this.f = f; } new Foo(function() { (function(x) { (function(y) { console.log(y); })(x); })(7); }).f(); } expect: { function Foo(f) { this.f = f; } new Foo(function() { !function(x) { !function(y) { console.log(y); }(x); }(7); }).f(); } expect_stdout: true } negate_iife_nested_off: { options = { negate_iife: false, sequences: true, conditionals: true, }; input: { function Foo(f) { this.f = f; } new Foo(function() { (function(x) { (function(y) { console.log(y); })(x); })(7); }).f(); } expect: { function Foo(f) { this.f = f; } new Foo(function() { (function(x) { (function(y) { console.log(y); })(x); })(7); }).f(); } expect_stdout: true } negate_iife_issue_1073: { options = { negate_iife: true, sequences: true, conditionals: true, }; input: { new (function(a) { return function Foo() { this.x = a; console.log(this); }; }(7))(); } expect: { new (function(a) { return function Foo() { this.x = a, console.log(this); }; }(7))(); } expect_stdout: true } issue_1254_negate_iife_false: { options = { negate_iife: false, } input: { (function() { return function() { console.log('test') }; })()(); } expect_exact: '(function(){return function(){console.log("test")}})()();' expect_stdout: true } issue_1254_negate_iife_true: { options = { negate_iife: true, } input: { (function() { return function() { console.log('test') }; })()(); } expect_exact: '!function(){return function(){console.log("test")}}()();' expect_stdout: true } issue_1254_negate_iife_nested: { options = { negate_iife: true, } input: { (function() { return function() { console.log('test') }; })()()()()(); } expect_exact: '!function(){return function(){console.log("test")}}()()()()();' expect_stdout: true } issue_1288: { options = { conditionals: true, negate_iife: true, side_effects: false, }; input: { if (w) ; else { (function f() {})(); } if (!x) { (function() { x = {}; })(); } if (y) (function() {})(); else (function(z) { return z; })(0); } expect: { w || !function f() {}(); x || !function() { x = {}; }(); y ? !function() {}() : !function(z) { return z; }(0); } } issue_1288_side_effects: { options = { conditionals: true, negate_iife: true, side_effects: true, } input: { if (w) ; else { (function f() {})(); } if (!x) { (function() { x = {}; })(); } if (y) (function() {})(); else (function(z) { return z; })(0); } expect: { w; x || function() { x = {}; }(); y; } } UglifyJS2-2.8.29/test/compress/new.js000066400000000000000000000050021312030606600173250ustar00rootroot00000000000000new_statement: { input: { new x(1); new x(1)(2); new x(1)(2)(3); new new x(1); new new x(1)(2); new (new x(1))(2); (new new x(1))(2); } expect_exact: "new x(1);new x(1)(2);new x(1)(2)(3);new new x(1);new new x(1)(2);new new x(1)(2);(new new x(1))(2);" } new_statements_2: { input: { new x; new new x; new new new x; new true; new (0); new (!0); new (bar = function(foo) {this.foo=foo;})(123); new (bar = function(foo) {this.foo=foo;})(); } expect_exact: "new x;new(new x);new(new(new x));new true;new 0;new(!0);new(bar=function(foo){this.foo=foo})(123);new(bar=function(foo){this.foo=foo});" } new_statements_3: { input: { new (function(foo){this.foo=foo;})(1); new (function(foo){this.foo=foo;})(); new (function test(foo){this.foo=foo;})(1); new (function test(foo){this.foo=foo;})(); } expect_exact: "new function(foo){this.foo=foo}(1);new function(foo){this.foo=foo};new function test(foo){this.foo=foo}(1);new function test(foo){this.foo=foo};" } new_with_rewritten_true_value: { options = { booleans: true } input: { new true; } expect_exact: "new(!0);" } new_with_many_parameters: { input: { new foo.bar("baz"); new x(/123/, 456); } expect_exact: 'new foo.bar("baz");new x(/123/,456);' } new_constructor_with_unary_arguments: { input: { new x(); new x(-1); new x(-1, -2); new x(void 1, +2, -3, ~4, !5, --a, ++b, c--, d++, typeof e, delete f); new (-1); // should parse despite being invalid at runtime. new (-1)(); // should parse despite being invalid at runtime. new (-1)(-2); // should parse despite being invalid at runtime. } expect_exact: "new x;new x(-1);new x(-1,-2);new x(void 1,+2,-3,~4,!5,--a,++b,c--,d++,typeof e,delete f);new(-1);new(-1);new(-1)(-2);" } call_with_unary_arguments: { input: { x(); x(-1); x(-1, -2); x(void 1, +2, -3, ~4, !5, --a, ++b, c--, d++, typeof e, delete f); (-1)(); // should parse despite being invalid at runtime. (-1)(-2); // should parse despite being invalid at runtime. } expect_exact: "x();x(-1);x(-1,-2);x(void 1,+2,-3,~4,!5,--a,++b,c--,d++,typeof e,delete f);(-1)();(-1)(-2);" } new_with_unary_prefix: { input: { var bar = (+new Date()).toString(32); } expect_exact: 'var bar=(+new Date).toString(32);'; } UglifyJS2-2.8.29/test/compress/numbers.js000066400000000000000000000077371312030606600202300ustar00rootroot00000000000000hex_numbers_in_parentheses_for_prototype_functions: { input: { (-2); (-2).toFixed(0); (2); (2).toFixed(0); (0.2); (0.2).toFixed(0); (0.00000002); (0.00000002).toFixed(0); (1000000000000000128); (1000000000000000128).toFixed(0); } expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);" } comparisons: { options = { comparisons: true, } input: { console.log( ~x === 42, x % n === 42 ); } expect: { console.log( 42 == ~x, x % n == 42 ); } } evaluate_1: { options = { evaluate: true, unsafe_math: false, } input: { console.log( x + 1 + 2, x * 1 * 2, +x + 1 + 2, 1 + x + 2 + 3, 1 | x | 2 | 3, 1 + x-- + 2 + 3, 1 + (x*y + 2) + 3, 1 + (2 + x + 3), 1 + (2 + ~x + 3), -y + (2 + ~x + 3), 1 & (2 & x & 3), 1 + (2 + (x |= 0) + 3) ); } expect: { console.log( x + 1 + 2, 1 * x * 2, +x + 1 + 2, 1 + x + 2 + 3, 3 | x, 1 + x-- + 2 + 3, x*y + 2 + 1 + 3, 1 + (2 + x + 3), 2 + ~x + 3 + 1, -y + (2 + ~x + 3), 0 & x, 2 + (x |= 0) + 3 + 1 ); } } evaluate_2: { options = { evaluate: true, unsafe_math: true, } input: { console.log( x + 1 + 2, x * 1 * 2, +x + 1 + 2, 1 + x + 2 + 3, 1 | x | 2 | 3, 1 + x-- + 2 + 3, 1 + (x*y + 2) + 3, 1 + (2 + x + 3), 1 & (2 & x & 3), 1 + (2 + (x |= 0) + 3) ); } expect: { console.log( x + 1 + 2, 2 * x, 3 + +x, 1 + x + 2 + 3, 3 | x, 6 + x--, 6 + x*y, 1 + (2 + x + 3), 0 & x, 6 + (x |= 0) ); } } evaluate_3: { options = { evaluate: true, unsafe: true, unsafe_math: true, } input: { console.log(1 + Number(x) + 2); } expect: { console.log(3 + +x); } } evaluate_4: { options = { evaluate: true, } input: { console.log( 1+ +a, +a+1, 1+-a, -a+1, +a+ +b, +a+-b, -a+ +b, -a+-b ); } expect: { console.log( +a+1, +a+1, 1-a, 1-a, +a+ +b, +a-b, -a+ +b, -a-b ); } } issue_1710: { options = { evaluate: true, } input: { var x = {}; console.log((x += 1) + -x); } expect: { var x = {}; console.log((x += 1) + -x); } expect_stdout: true } unary_binary_parenthesis: { input: { var v = [ 0, 1, NaN, Infinity, null, undefined, true, false, "", "foo", /foo/ ]; v.forEach(function(x) { v.forEach(function(y) { console.log( +(x*y), +(x/y), +(x%y), -(x*y), -(x/y), -(x%y) ); }); }); } expect: { var v = [ 0, 1, NaN, 1/0, null, void 0, true, false, "", "foo", /foo/ ]; v.forEach(function(x) { v.forEach(function(y) { console.log( +x*y, +x/y, +x%y, -x*y, -x/y, -x%y ); }); }); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/properties.js000066400000000000000000000660501312030606600207420ustar00rootroot00000000000000keep_properties: { options = { properties: false }; input: { a["foo"] = "bar"; } expect: { a["foo"] = "bar"; } } dot_properties: { options = { properties: true, screw_ie8: false }; input: { a["foo"] = "bar"; a["if"] = "if"; a["*"] = "asterisk"; a["\u0EB3"] = "unicode"; a[""] = "whitespace"; a["1_1"] = "foo"; } expect: { a.foo = "bar"; a["if"] = "if"; a["*"] = "asterisk"; a["\u0EB3"] = "unicode"; a[""] = "whitespace"; a["1_1"] = "foo"; } } dot_properties_es5: { options = { properties: true, screw_ie8: true }; input: { a["foo"] = "bar"; a["if"] = "if"; a["*"] = "asterisk"; a["\u0EB3"] = "unicode"; a[""] = "whitespace"; } expect: { a.foo = "bar"; a.if = "if"; a["*"] = "asterisk"; a["\u0EB3"] = "unicode"; a[""] = "whitespace"; } } sub_properties: { options = { evaluate: true, properties: true }; input: { a[0] = 0; a["0"] = 1; a[3.14] = 2; a["3" + ".14"] = 3; a["i" + "f"] = 4; a["foo" + " bar"] = 5; a[0 / 0] = 6; a[null] = 7; a[undefined] = 8; } expect: { a[0] = 0; a[0] = 1; a[3.14] = 2; a[3.14] = 3; a.if = 4; a["foo bar"] = 5; a[NaN] = 6; a[null] = 7; a[void 0] = 8; } } evaluate_array_length: { options = { properties: true, unsafe: true, evaluate: true }; input: { a = [1, 2, 3].length; a = [1, 2, 3].join()["len" + "gth"]; a = [1, 2, b].length; a = [1, 2, 3].join(b).length; } expect: { a = 3; a = 5; a = [1, 2, b].length; a = [1, 2, 3].join(b).length; } } evaluate_string_length: { options = { properties: true, unsafe: true, evaluate: true }; input: { a = "foo".length; a = ("foo" + "bar")["len" + "gth"]; a = b.length; a = ("foo" + b).length; } expect: { a = 3; a = 6; a = b.length; a = ("foo" + b).length; } } mangle_properties: { mangle_props = { ignore_quoted: false }; input: { a["foo"] = "bar"; a.color = "red"; x = {"bar": 10}; a.run(x.bar, a.foo); a['run']({color: "blue", foo: "baz"}); } expect: { a["a"] = "bar"; a.b = "red"; x = {c: 10}; a.d(x.c, a.a); a['d']({b: "blue", a: "baz"}); } } mangle_unquoted_properties: { options = { properties: false } mangle_props = { ignore_quoted: true } beautify = { beautify: false, quote_style: 3, keep_quoted_props: true, } input: { a.top = 1; function f1() { a["foo"] = "bar"; a.color = "red"; a.stuff = 2; x = {"bar": 10, size: 7}; a.size = 9; } function f2() { a.foo = "bar"; a['color'] = "red"; x = {bar: 10, size: 7}; a.size = 9; a.stuff = 3; } } expect: { a.a = 1; function f1() { a["foo"] = "bar"; a.color = "red"; a.b = 2; x = {"bar": 10, c: 7}; a.c = 9; } function f2() { a.foo = "bar"; a['color'] = "red"; x = {bar: 10, c: 7}; a.c = 9; a.b = 3; } } } mangle_debug: { mangle_props = { debug: "" }; input: { a.foo = "bar"; x = { baz: "ban" }; } expect: { a._$foo$_ = "bar"; x = { _$baz$_: "ban" }; } } mangle_debug_true: { mangle_props = { debug: true }; input: { a.foo = "bar"; x = { baz: "ban" }; } expect: { a._$foo$_ = "bar"; x = { _$baz$_: "ban" }; } } mangle_debug_suffix: { mangle_props = { debug: "XYZ" }; input: { a.foo = "bar"; x = { baz: "ban" }; } expect: { a._$foo$XYZ_ = "bar"; x = { _$baz$XYZ_: "ban" }; } } mangle_debug_suffix_ignore_quoted: { options = { properties: false } mangle_props = { ignore_quoted: true, debug: "XYZ", reserved: [] } beautify = { beautify: false, quote_style: 3, keep_quoted_props: true, } input: { a.top = 1; function f1() { a["foo"] = "bar"; a.color = "red"; a.stuff = 2; x = {"bar": 10, size: 7}; a.size = 9; } function f2() { a.foo = "bar"; a['color'] = "red"; x = {bar: 10, size: 7}; a.size = 9; a.stuff = 3; } } expect: { a._$top$XYZ_ = 1; function f1() { a["foo"] = "bar"; a.color = "red"; a._$stuff$XYZ_ = 2; x = {"bar": 10, _$size$XYZ_: 7}; a._$size$XYZ_ = 9; } function f2() { a.foo = "bar"; a['color'] = "red"; x = {bar: 10, _$size$XYZ_: 7}; a._$size$XYZ_ = 9; a._$stuff$XYZ_ = 3; } } } first_256_chars_as_properties: { beautify = { ascii_only: true, } input: { // Note: some of these unicode character keys are not visible on github.com var o = { "\0":0,"":1,"":2,"":3,"":4,"":5,"":6,"":7,"\b":8, "\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"":14,"":15,"":16,"":17, "":18,"":19,"":20,"":21,"":22,"":23,"":24,"":25,"":26, "":27,"":28,"":29,"":30,"":31," ":32,"!":33,'"':34,"#":35, $:36,"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44, "-":45,".":46,"/":47,"0":48,"1":49,"2":50,"3":51,"4":52,"5":53,"6":54,"7":55, "8":56,"9":57,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65, B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78, O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91, "\\":92,"]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101, f:102,g:103,h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112, q:113,r:114,s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123, "|":124,"}":125,"~":126,"":127,"€":128,"":129,"‚":130,"ƒ":131, "„":132,"…":133,"†":134,"‡":135,"ˆ":136,"‰":137,"Š":138,"‹":139, "Œ":140,"":141,"Ž":142,"":143,"":144,"‘":145,"’":146,"“":147, "”":148,"•":149,"–":150,"—":151,"˜":152,"™":153,"š":154,"›":155, "œ":156,"":157,"ž":158,"Ÿ":159," ":160,"¡":161,"¢":162,"£":163, "¤":164,"¥":165,"¦":166,"§":167,"¨":168,"©":169,"ª":170,"«":171, "¬":172,"­":173,"®":174,"¯":175,"°":176,"±":177,"²":178,"³":179, "´":180,"µ":181,"¶":182,"·":183,"¸":184,"¹":185,"º":186,"»":187, "¼":188,"½":189,"¾":190,"¿":191,"À":192,"Á":193,"Â":194,"Ã":195, "Ä":196,"Å":197,"Æ":198,"Ç":199,"È":200,"É":201,"Ê":202,"Ë":203, "Ì":204,"Í":205,"Î":206,"Ï":207,"Ð":208,"Ñ":209,"Ò":210,"Ó":211, "Ô":212,"Õ":213,"Ö":214,"×":215,"Ø":216,"Ù":217,"Ú":218,"Û":219, "Ü":220,"Ý":221,"Þ":222,"ß":223,"à":224,"á":225,"â":226,"ã":227, "ä":228,"å":229,"æ":230,"ç":231,"è":232,"é":233,"ê":234,"ë":235, "ì":236,"í":237,"î":238,"ï":239,"ð":240,"ñ":241,"ò":242,"ó":243, "ô":244,"õ":245,"ö":246,"÷":247,"ø":248,"ù":249,"ú":250,"û":251, "ü":252,"ý":253,"þ":254,"ÿ":255 }; } expect: { var o = { "\0":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6, "\x07":7,"\b":8,"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"\x0e":14, "\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21, "\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28, "\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,$:36, "%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45, ".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57, ":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,B:66,C:67, D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80, Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,"\\":92, "]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,f:102,g:103, h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,q:113,r:114, s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,"|":124, "}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131, "\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137, "\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143, "\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149, "\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155, "\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161, "\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167, "\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173, "\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179, "\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185, "\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191, "\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197, "\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203, "\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209, "\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215, "\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221, "\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227, "\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233, "\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239, "\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245, "\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251, "\xfc":252,"\xfd":253,"\xfe":254,"\xff":255 }; } } first_256_unicode_chars_as_properties: { input: { var o = { "\u0000": 0, "\u0001": 1, "\u0002": 2, "\u0003": 3, "\u0004": 4, "\u0005": 5, "\u0006": 6, "\u0007": 7, "\u0008": 8, "\u0009": 9, "\u000A": 10, "\u000B": 11, "\u000C": 12, "\u000D": 13, "\u000E": 14, "\u000F": 15, "\u0010": 16, "\u0011": 17, "\u0012": 18, "\u0013": 19, "\u0014": 20, "\u0015": 21, "\u0016": 22, "\u0017": 23, "\u0018": 24, "\u0019": 25, "\u001A": 26, "\u001B": 27, "\u001C": 28, "\u001D": 29, "\u001E": 30, "\u001F": 31, "\u0020": 32, "\u0021": 33, "\u0022": 34, "\u0023": 35, "\u0024": 36, "\u0025": 37, "\u0026": 38, "\u0027": 39, "\u0028": 40, "\u0029": 41, "\u002A": 42, "\u002B": 43, "\u002C": 44, "\u002D": 45, "\u002E": 46, "\u002F": 47, "\u0030": 48, "\u0031": 49, "\u0032": 50, "\u0033": 51, "\u0034": 52, "\u0035": 53, "\u0036": 54, "\u0037": 55, "\u0038": 56, "\u0039": 57, "\u003A": 58, "\u003B": 59, "\u003C": 60, "\u003D": 61, "\u003E": 62, "\u003F": 63, "\u0040": 64, "\u0041": 65, "\u0042": 66, "\u0043": 67, "\u0044": 68, "\u0045": 69, "\u0046": 70, "\u0047": 71, "\u0048": 72, "\u0049": 73, "\u004A": 74, "\u004B": 75, "\u004C": 76, "\u004D": 77, "\u004E": 78, "\u004F": 79, "\u0050": 80, "\u0051": 81, "\u0052": 82, "\u0053": 83, "\u0054": 84, "\u0055": 85, "\u0056": 86, "\u0057": 87, "\u0058": 88, "\u0059": 89, "\u005A": 90, "\u005B": 91, "\u005C": 92, "\u005D": 93, "\u005E": 94, "\u005F": 95, "\u0060": 96, "\u0061": 97, "\u0062": 98, "\u0063": 99, "\u0064": 100, "\u0065": 101, "\u0066": 102, "\u0067": 103, "\u0068": 104, "\u0069": 105, "\u006A": 106, "\u006B": 107, "\u006C": 108, "\u006D": 109, "\u006E": 110, "\u006F": 111, "\u0070": 112, "\u0071": 113, "\u0072": 114, "\u0073": 115, "\u0074": 116, "\u0075": 117, "\u0076": 118, "\u0077": 119, "\u0078": 120, "\u0079": 121, "\u007A": 122, "\u007B": 123, "\u007C": 124, "\u007D": 125, "\u007E": 126, "\u007F": 127, "\u0080": 128, "\u0081": 129, "\u0082": 130, "\u0083": 131, "\u0084": 132, "\u0085": 133, "\u0086": 134, "\u0087": 135, "\u0088": 136, "\u0089": 137, "\u008A": 138, "\u008B": 139, "\u008C": 140, "\u008D": 141, "\u008E": 142, "\u008F": 143, "\u0090": 144, "\u0091": 145, "\u0092": 146, "\u0093": 147, "\u0094": 148, "\u0095": 149, "\u0096": 150, "\u0097": 151, "\u0098": 152, "\u0099": 153, "\u009A": 154, "\u009B": 155, "\u009C": 156, "\u009D": 157, "\u009E": 158, "\u009F": 159, "\u00A0": 160, "\u00A1": 161, "\u00A2": 162, "\u00A3": 163, "\u00A4": 164, "\u00A5": 165, "\u00A6": 166, "\u00A7": 167, "\u00A8": 168, "\u00A9": 169, "\u00AA": 170, "\u00AB": 171, "\u00AC": 172, "\u00AD": 173, "\u00AE": 174, "\u00AF": 175, "\u00B0": 176, "\u00B1": 177, "\u00B2": 178, "\u00B3": 179, "\u00B4": 180, "\u00B5": 181, "\u00B6": 182, "\u00B7": 183, "\u00B8": 184, "\u00B9": 185, "\u00BA": 186, "\u00BB": 187, "\u00BC": 188, "\u00BD": 189, "\u00BE": 190, "\u00BF": 191, "\u00C0": 192, "\u00C1": 193, "\u00C2": 194, "\u00C3": 195, "\u00C4": 196, "\u00C5": 197, "\u00C6": 198, "\u00C7": 199, "\u00C8": 200, "\u00C9": 201, "\u00CA": 202, "\u00CB": 203, "\u00CC": 204, "\u00CD": 205, "\u00CE": 206, "\u00CF": 207, "\u00D0": 208, "\u00D1": 209, "\u00D2": 210, "\u00D3": 211, "\u00D4": 212, "\u00D5": 213, "\u00D6": 214, "\u00D7": 215, "\u00D8": 216, "\u00D9": 217, "\u00DA": 218, "\u00DB": 219, "\u00DC": 220, "\u00DD": 221, "\u00DE": 222, "\u00DF": 223, "\u00E0": 224, "\u00E1": 225, "\u00E2": 226, "\u00E3": 227, "\u00E4": 228, "\u00E5": 229, "\u00E6": 230, "\u00E7": 231, "\u00E8": 232, "\u00E9": 233, "\u00EA": 234, "\u00EB": 235, "\u00EC": 236, "\u00ED": 237, "\u00EE": 238, "\u00EF": 239, "\u00F0": 240, "\u00F1": 241, "\u00F2": 242, "\u00F3": 243, "\u00F4": 244, "\u00F5": 245, "\u00F6": 246, "\u00F7": 247, "\u00F8": 248, "\u00F9": 249, "\u00FA": 250, "\u00FB": 251, "\u00FC": 252, "\u00FD": 253, "\u00FE": 254, "\u00FF": 255 }; } expect: { var o = { "\0":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6, "\x07":7,"\b":8,"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"\x0e":14, "\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21, "\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28, "\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,$:36, "%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45, ".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57, ":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,B:66,C:67, D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80, Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,"\\":92, "]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,f:102,g:103, h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,q:113,r:114, s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,"|":124, "}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131, "\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137, "\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143, "\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149, "\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155, "\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161, "\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167, "\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173, "\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179, "\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185, "\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191, "\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197, "\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203, "\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209, "\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215, "\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221, "\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227, "\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233, "\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239, "\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245, "\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251, "\xfc":252,"\xfd":253,"\xfe":254,"\xff":255 }; } } first_256_hex_chars_as_properties: { input: { var o = { "\x00": 0, "\x01": 1, "\x02": 2, "\x03": 3, "\x04": 4, "\x05": 5, "\x06": 6, "\x07": 7, "\x08": 8, "\x09": 9, "\x0A": 10, "\x0B": 11, "\x0C": 12, "\x0D": 13, "\x0E": 14, "\x0F": 15, "\x10": 16, "\x11": 17, "\x12": 18, "\x13": 19, "\x14": 20, "\x15": 21, "\x16": 22, "\x17": 23, "\x18": 24, "\x19": 25, "\x1A": 26, "\x1B": 27, "\x1C": 28, "\x1D": 29, "\x1E": 30, "\x1F": 31, "\x20": 32, "\x21": 33, "\x22": 34, "\x23": 35, "\x24": 36, "\x25": 37, "\x26": 38, "\x27": 39, "\x28": 40, "\x29": 41, "\x2A": 42, "\x2B": 43, "\x2C": 44, "\x2D": 45, "\x2E": 46, "\x2F": 47, "\x30": 48, "\x31": 49, "\x32": 50, "\x33": 51, "\x34": 52, "\x35": 53, "\x36": 54, "\x37": 55, "\x38": 56, "\x39": 57, "\x3A": 58, "\x3B": 59, "\x3C": 60, "\x3D": 61, "\x3E": 62, "\x3F": 63, "\x40": 64, "\x41": 65, "\x42": 66, "\x43": 67, "\x44": 68, "\x45": 69, "\x46": 70, "\x47": 71, "\x48": 72, "\x49": 73, "\x4A": 74, "\x4B": 75, "\x4C": 76, "\x4D": 77, "\x4E": 78, "\x4F": 79, "\x50": 80, "\x51": 81, "\x52": 82, "\x53": 83, "\x54": 84, "\x55": 85, "\x56": 86, "\x57": 87, "\x58": 88, "\x59": 89, "\x5A": 90, "\x5B": 91, "\x5C": 92, "\x5D": 93, "\x5E": 94, "\x5F": 95, "\x60": 96, "\x61": 97, "\x62": 98, "\x63": 99, "\x64": 100, "\x65": 101, "\x66": 102, "\x67": 103, "\x68": 104, "\x69": 105, "\x6A": 106, "\x6B": 107, "\x6C": 108, "\x6D": 109, "\x6E": 110, "\x6F": 111, "\x70": 112, "\x71": 113, "\x72": 114, "\x73": 115, "\x74": 116, "\x75": 117, "\x76": 118, "\x77": 119, "\x78": 120, "\x79": 121, "\x7A": 122, "\x7B": 123, "\x7C": 124, "\x7D": 125, "\x7E": 126, "\x7F": 127, "\x80": 128, "\x81": 129, "\x82": 130, "\x83": 131, "\x84": 132, "\x85": 133, "\x86": 134, "\x87": 135, "\x88": 136, "\x89": 137, "\x8A": 138, "\x8B": 139, "\x8C": 140, "\x8D": 141, "\x8E": 142, "\x8F": 143, "\x90": 144, "\x91": 145, "\x92": 146, "\x93": 147, "\x94": 148, "\x95": 149, "\x96": 150, "\x97": 151, "\x98": 152, "\x99": 153, "\x9A": 154, "\x9B": 155, "\x9C": 156, "\x9D": 157, "\x9E": 158, "\x9F": 159, "\xA0": 160, "\xA1": 161, "\xA2": 162, "\xA3": 163, "\xA4": 164, "\xA5": 165, "\xA6": 166, "\xA7": 167, "\xA8": 168, "\xA9": 169, "\xAA": 170, "\xAB": 171, "\xAC": 172, "\xAD": 173, "\xAE": 174, "\xAF": 175, "\xB0": 176, "\xB1": 177, "\xB2": 178, "\xB3": 179, "\xB4": 180, "\xB5": 181, "\xB6": 182, "\xB7": 183, "\xB8": 184, "\xB9": 185, "\xBA": 186, "\xBB": 187, "\xBC": 188, "\xBD": 189, "\xBE": 190, "\xBF": 191, "\xC0": 192, "\xC1": 193, "\xC2": 194, "\xC3": 195, "\xC4": 196, "\xC5": 197, "\xC6": 198, "\xC7": 199, "\xC8": 200, "\xC9": 201, "\xCA": 202, "\xCB": 203, "\xCC": 204, "\xCD": 205, "\xCE": 206, "\xCF": 207, "\xD0": 208, "\xD1": 209, "\xD2": 210, "\xD3": 211, "\xD4": 212, "\xD5": 213, "\xD6": 214, "\xD7": 215, "\xD8": 216, "\xD9": 217, "\xDA": 218, "\xDB": 219, "\xDC": 220, "\xDD": 221, "\xDE": 222, "\xDF": 223, "\xE0": 224, "\xE1": 225, "\xE2": 226, "\xE3": 227, "\xE4": 228, "\xE5": 229, "\xE6": 230, "\xE7": 231, "\xE8": 232, "\xE9": 233, "\xEA": 234, "\xEB": 235, "\xEC": 236, "\xED": 237, "\xEE": 238, "\xEF": 239, "\xF0": 240, "\xF1": 241, "\xF2": 242, "\xF3": 243, "\xF4": 244, "\xF5": 245, "\xF6": 246, "\xF7": 247, "\xF8": 248, "\xF9": 249, "\xFA": 250, "\xFB": 251, "\xFC": 252, "\xFD": 253, "\xFE": 254, "\xFF": 255 }; } expect: { var o = { "\0":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6, "\x07":7,"\b":8,"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"\x0e":14, "\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21, "\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28, "\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,$:36, "%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45, ".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57, ":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,B:66,C:67, D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80, Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,"\\":92, "]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,f:102,g:103, h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,q:113,r:114, s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,"|":124, "}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131, "\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137, "\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143, "\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149, "\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155, "\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161, "\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167, "\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173, "\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179, "\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185, "\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191, "\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197, "\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203, "\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209, "\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215, "\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221, "\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227, "\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233, "\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239, "\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245, "\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251, "\xfc":252,"\xfd":253,"\xfe":254,"\xff":255 }; } } native_prototype: { options = { unsafe_proto: true, } input: { Array.prototype.splice.apply(a, [1, 2, b, c]); Object.prototype.hasOwnProperty.call(d, "foo"); String.prototype.indexOf.call(e, "bar"); } expect: { [].splice.apply(a, [1, 2, b, c]); ({}).hasOwnProperty.call(d, "foo"); "".indexOf.call(e, "bar"); } } accessor_boolean: { input: { var a = 1; var b = { get true() { return a; }, set false(c) { a = c; } }; console.log(b.true, b.false = 2, b.true); } expect_exact: 'var a=1;var b={get true(){return a},set false(c){a=c}};console.log(b.true,b.false=2,b.true);' expect_stdout: "1 2 2" } accessor_get_set: { input: { var a = 1; var b = { get set() { return a; }, set get(c) { a = c; } }; console.log(b.set, b.get = 2, b.set); } expect_exact: 'var a=1;var b={get set(){return a},set get(c){a=c}};console.log(b.set,b.get=2,b.set);' expect_stdout: "1 2 2" } accessor_null_undefined: { input: { var a = 1; var b = { get null() { return a; }, set undefined(c) { a = c; } }; console.log(b.null, b.undefined = 2, b.null); } expect_exact: 'var a=1;var b={get null(){return a},set undefined(c){a=c}};console.log(b.null,b.undefined=2,b.null);' expect_stdout: "1 2 2" } accessor_number: { input: { var a = 1; var b = { get 42() { return a; }, set 42(c) { a = c; } }; console.log(b[42], b[42] = 2, b[42]); } expect_exact: 'var a=1;var b={get 42(){return a},set 42(c){a=c}};console.log(b[42],b[42]=2,b[42]);' expect_stdout: "1 2 2" } accessor_string: { input: { var a = 1; var b = { get "a-b"() { return a; }, set "a-b"(c) { a = c; } }; console.log(b["a-b"], b["a-b"] = 2, b["a-b"]); } expect_exact: 'var a=1;var b={get"a-b"(){return a},set"a-b"(c){a=c}};console.log(b["a-b"],b["a-b"]=2,b["a-b"]);' expect_stdout: "1 2 2" } accessor_this: { input: { var a = 1; var b = { get this() { return a; }, set this(c) { a = c; } }; console.log(b.this, b.this = 2, b.this); } expect_exact: 'var a=1;var b={get this(){return a},set this(c){a=c}};console.log(b.this,b.this=2,b.this);' expect_stdout: "1 2 2" } UglifyJS2-2.8.29/test/compress/pure_funcs.js000066400000000000000000000127311312030606600207140ustar00rootroot00000000000000array: { options = { pure_funcs: [ "Math.floor" ], side_effects: true, } input: { var a; function f(b) { Math.floor(a / b); Math.floor(c / b); } } expect: { var a; function f(b) { c; } } } func: { options = { pure_funcs: function(node) { return !~node.args[0].print_to_string().indexOf("a"); }, side_effects: true, } input: { function f(a, b) { Math.floor(a / b); Math.floor(c / b); } } expect: { function f(a, b) { Math.floor(c / b); } } } side_effects: { options = { pure_funcs: [ "console.log" ], side_effects: true, } input: { function f(a, b) { console.log(a()); console.log(b); } } expect: { function f(a, b) { a(); } } } unused: { options = { pure_funcs: [ "pure" ], side_effects: true, unused: true, } input: { function foo() { var u = pure(1); var x = pure(2); var y = pure(x); var z = pure(pure(side_effects())); return pure(3); } } expect: { function foo() { side_effects(); return pure(3); } } } babel: { options = { pure_funcs: [ "_classCallCheck" ], side_effects: true, unused: true, } input: { function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); } var Foo = function Foo() { _classCallCheck(this, Foo); }; } expect: { function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function"); } var Foo = function() { }; } } conditional: { options = { pure_funcs: [ "pure" ], side_effects: true, } input: { pure(1 | a() ? 2 & b() : 7 ^ c()); pure(1 | a() ? 2 & b() : 5); pure(1 | a() ? 4 : 7 ^ c()); pure(1 | a() ? 4 : 5); pure(3 ? 2 & b() : 7 ^ c()); pure(3 ? 2 & b() : 5); pure(3 ? 4 : 7 ^ c()); pure(3 ? 4 : 5); } expect: { 1 | a() ? b() : c(); 1 | a() && b(); 1 | a() || c(); a(); 3 ? b() : c(); 3 && b(); 3 || c(); } } relational: { options = { pure_funcs: [ "foo" ], side_effects :true, } input: { foo() in foo(); foo() instanceof bar(); foo() < "bar"; bar() > foo(); bar() != bar(); bar() !== "bar"; "bar" == foo(); "bar" === bar(); "bar" >= "bar"; } expect: { bar(); bar(); bar(), bar(); bar(); bar(); } } arithmetic: { options = { pure_funcs: [ "foo" ], side_effects :true, } input: { foo() + foo(); foo() - bar(); foo() * "bar"; bar() / foo(); bar() & bar(); bar() | "bar"; "bar" >> foo(); "bar" << bar(); "bar" >>> "bar"; } expect: { bar(); bar(); bar(), bar(); bar(); bar(); } } boolean_and: { options = { pure_funcs: [ "foo" ], side_effects :true, } input: { foo() && foo(); foo() && bar(); foo() && "bar"; bar() && foo(); bar() && bar(); bar() && "bar"; "bar" && foo(); "bar" && bar(); "bar" && "bar"; } expect: { foo() && bar(); bar(); bar() && bar(); bar(); "bar" && bar(); } } boolean_or: { options = { pure_funcs: [ "foo" ], side_effects :true, } input: { foo() || foo(); foo() || bar(); foo() || "bar"; bar() || foo(); bar() || bar(); bar() || "bar"; "bar" || foo(); "bar" || bar(); "bar" || "bar"; } expect: { foo() || bar(); bar(); bar() || bar(); bar(); "bar" || bar(); } } assign: { options = { pure_funcs: [ "foo" ], side_effects :true, } input: { var a; function f(b) { a = foo(); b *= 4 + foo(); c >>= 0 | foo(); } } expect: { var a; function f(b) { a = foo(); b *= 4 + foo(); c >>= 0 | foo(); } } } unary: { options = { pure_funcs: [ "foo" ], side_effects :true, } input: { typeof foo(); typeof bar(); typeof "bar"; void foo(); void bar(); void "bar"; delete a[foo()]; delete a[bar()]; delete a["bar"]; a[foo()]++; a[bar()]++; a["bar"]++; --a[foo()]; --a[bar()]; --a["bar"]; ~foo(); ~bar(); ~"bar"; } expect: { bar(); bar(); delete a[foo()]; delete a[bar()]; delete a["bar"]; a[foo()]++; a[bar()]++; a["bar"]++; --a[foo()]; --a[bar()]; --a["bar"]; bar(); } } UglifyJS2-2.8.29/test/compress/pure_getters.js000066400000000000000000000060761312030606600212600ustar00rootroot00000000000000strict: { options = { pure_getters: "strict", reduce_vars: false, side_effects: true, toplevel: true, } input: { var a, b = null, c = {}; a.prop; b.prop; c.prop; d.prop; null.prop; (void 0).prop; undefined.prop; } expect: { var a, b = null, c = {}; a.prop; b.prop; c.prop; d.prop; null.prop; (void 0).prop; (void 0).prop; } } strict_reduce_vars: { options = { pure_getters: "strict", reduce_vars: true, side_effects: true, toplevel: true, } input: { var a, b = null, c = {}; a.prop; b.prop; c.prop; d.prop; null.prop; (void 0).prop; undefined.prop; } expect: { var a, b = null, c = {}; a.prop; b.prop; d.prop; null.prop; (void 0).prop; (void 0).prop; } } unsafe: { options = { pure_getters: true, reduce_vars: false, side_effects: true, toplevel: true, } input: { var a, b = null, c = {}; a.prop; b.prop; c.prop; d.prop; null.prop; (void 0).prop; undefined.prop; } expect: { var a, b = null, c = {}; d; null.prop; (void 0).prop; (void 0).prop; } } unsafe_reduce_vars: { options = { pure_getters: true, reduce_vars: true, side_effects: true, toplevel: true, } input: { var a, b = null, c = {}; a.prop; b.prop; c.prop; d.prop; null.prop; (void 0).prop; undefined.prop; } expect: { var a, b = null, c = {}; d; null.prop; (void 0).prop; (void 0).prop; } } chained: { options = { pure_getters: "strict", side_effects: true, } input: { a.b.c; } expect: { a.b.c; } } impure_getter_1: { options = { pure_getters: "strict", side_effects: true, } input: { ({ get a() { console.log(1); }, b: 1 }).a; ({ get a() { console.log(1); }, b: 1 }).b; } expect: { ({ get a() { console.log(1); }, b: 1 }).a; ({ get a() { console.log(1); }, b: 1 }).b; } expect_stdout: "1" } impure_getter_2: { options = { pure_getters: true, side_effects: true, } input: { // will produce incorrect output because getter is not pure ({ get a() { console.log(1); }, b: 1 }).a; ({ get a() { console.log(1); }, b: 1 }).b; } expect: {} } UglifyJS2-2.8.29/test/compress/reduce_vars.js000066400000000000000000001237261312030606600210540ustar00rootroot00000000000000reduce_vars: { options = { conditionals : true, evaluate : true, global_defs : { C : 0 }, reduce_vars : true, toplevel : true, unused : true } input: { var A = 1; (function f0() { var a = 2; console.log(a - 5); console.log(A - 5); })(); (function f1() { var a = 2; console.log(a - 5); eval("console.log(a);"); })(); (function f2(eval) { var a = 2; console.log(a - 5); eval("console.log(a);"); })(eval); (function f3() { var b = typeof C !== "undefined"; var c = 4; if (b) { return 'yes'; } else { return 'no'; } })(); console.log(A + 1); } expect: { var A = 1; (function() { console.log(-3); console.log(A - 5); })(); (function f1() { var a = 2; console.log(a - 5); eval("console.log(a);"); })(); (function f2(eval) { var a = 2; console.log(a - 5); eval("console.log(a);"); })(eval); (function() { return "yes"; })(); console.log(A + 1); } expect_stdout: true } modified: { options = { conditionals : true, evaluate : true, reduce_vars : true, unused : true } input: { function f0() { var a = 1, b = 2; b++; console.log(a + 1); console.log(b + 1); } function f1() { var a = 1, b = 2; --b; console.log(a + 1); console.log(b + 1); } function f2() { var a = 1, b = 2, c = 3; b = c; console.log(a + b); console.log(b + c); console.log(a + c); console.log(a + b + c); } function f3() { var a = 1, b = 2, c = 3; b *= c; console.log(a + b); console.log(b + c); console.log(a + c); console.log(a + b + c); } function f4() { var a = 1, b = 2, c = 3; if (a) { b = c; } else { c = b; } console.log(a + b); console.log(b + c); console.log(a + c); console.log(a + b + c); } function f5(a) { B = a; console.log(A ? 'yes' : 'no'); console.log(B ? 'yes' : 'no'); } } expect: { function f0() { var b = 2; b++; console.log(2); console.log(b + 1); } function f1() { var b = 2; --b; console.log(2); console.log(b + 1); } function f2() { var b = 2; b = 3; console.log(1 + b); console.log(b + 3); console.log(4); console.log(1 + b + 3); } function f3() { var b = 2; b *= 3; console.log(1 + b); console.log(b + 3); console.log(4); console.log(1 + b + 3); } function f4() { var b = 2, c = 3; b = c; console.log(1 + b); console.log(b + c); console.log(1 + c); console.log(1 + b + c); } function f5(a) { B = a; console.log(A ? 'yes' : 'no'); console.log(B ? 'yes' : 'no'); } } } unsafe_evaluate: { options = { evaluate : true, reduce_vars : true, unsafe : true, unused : true } input: { function f0(){ var a = { b:1 }; console.log(a.b + 3); } function f1(){ var a = { b:{ c:1 }, d:2 }; console.log(a.b + 3, a.d + 4, a.b.c + 5, a.d.c + 6); } } expect: { function f0(){ console.log(4); } function f1(){ var a = { b:{ c:1 }, d:2 }; console.log(a.b + 3, 6, 6, 2..c + 6); } } } unsafe_evaluate_object: { options = { evaluate : true, reduce_vars : true, unsafe : true } input: { function f0(){ var a = 1; var b = {}; b[a] = 2; console.log(a + 3); } function f1(){ var a = { b:1 }; a.b = 2; console.log(a.b + 3); } } expect: { function f0(){ var a = 1; var b = {}; b[1] = 2; console.log(4); } function f1(){ var a = { b:1 }; a.b = 2; console.log(a.b + 3); } } } unsafe_evaluate_array: { options = { evaluate : true, reduce_vars : true, unsafe : true } input: { function f0(){ var a = 1; var b = []; b[a] = 2; console.log(a + 3); } function f1(){ var a = [1]; a[2] = 3; console.log(a.length); } function f2(){ var a = [1]; a.push(2); console.log(a.length); } } expect: { function f0(){ var a = 1; var b = []; b[1] = 2; console.log(4); } function f1(){ var a = [1]; a[2] = 3; console.log(a.length); } function f2(){ var a = [1]; a.push(2); console.log(a.length); } } } unsafe_evaluate_equality_1: { options = { evaluate : true, reduce_vars : true, unsafe : true, unused : true } input: { function f0() { var a = {}; return a === a; } function f1() { var a = []; return a === a; } console.log(f0(), f1()); } expect: { function f0() { return true; } function f1() { return true; } console.log(f0(), f1()); } expect_stdout: true } unsafe_evaluate_equality_2: { options = { collapse_vars: true, evaluate : true, passes : 2, reduce_vars : true, unsafe : true, unused : true } input: { function f2() { var a = {a:1, b:2}; var b = a; var c = a; return b === c; } function f3() { var a = [1, 2, 3]; var b = a; var c = a; return b === c; } console.log(f2(), f3()); } expect: { function f2() { return true; } function f3() { return true; } console.log(f2(), f3()); } expect_stdout: true } passes: { options = { conditionals: true, evaluate: true, passes: 2, reduce_vars: true, unused: true, } input: { function f() { var a = 1, b = 2, c = 3; if (a) { b = c; } else { c = b; } console.log(a + b); console.log(b + c); console.log(a + c); console.log(a + b + c); } } expect: { function f() { var b = 2; b = 3; console.log(1 + b); console.log(b + 3); console.log(4); console.log(1 + b + 3); } } } iife: { options = { evaluate: true, reduce_vars: true, } input: { !function(a, b, c) { b++; console.log(a - 1, b * 1, c + 2); }(1, 2, 3); } expect: { !function(a, b, c) { b++; console.log(0, 1 * b, 5); }(1, 2, 3); } expect_stdout: true } iife_new: { options = { evaluate: true, reduce_vars: true, } input: { var A = new function(a, b, c) { b++; console.log(a - 1, b * 1, c + 2); }(1, 2, 3); } expect: { var A = new function(a, b, c) { b++; console.log(0, 1 * b, 5); }(1, 2, 3); } expect_stdout: true } multi_def_1: { options = { evaluate: true, reduce_vars: true, } input: { function f(a) { if (a) var b = 1; else var b = 2; console.log(b + 1); } } expect: { function f(a) { if (a) var b = 1; else var b = 2; console.log(b + 1); } } } multi_def_2: { options = { evaluate: true, reduce_vars: true, } input: { function f(){ if (code == 16) var bitsLength = 2, bitsOffset = 3, what = len; else if (code == 17) var bitsLength = 3, bitsOffset = 3, what = (len = 0); else if (code == 18) var bitsLength = 7, bitsOffset = 11, what = (len = 0); var repeatLength = this.getBits(bitsLength) + bitsOffset; } } expect: { function f(){ if (16 == code) var bitsLength = 2, bitsOffset = 3, what = len; else if (17 == code) var bitsLength = 3, bitsOffset = 3, what = (len = 0); else if (18 == code) var bitsLength = 7, bitsOffset = 11, what = (len = 0); var repeatLength = this.getBits(bitsLength) + bitsOffset; } } } multi_def_3: { options = { evaluate: true, reduce_vars: true, } input: { function f(a) { var b = 2; if (a) var b; else var b; console.log(b + 1); } } expect: { function f(a) { var b = 2; if (a) var b; else var b; console.log(3); } } } use_before_var: { options = { evaluate: true, reduce_vars: true, } input: { function f(){ console.log(t); var t = 1; } } expect: { function f(){ console.log(t); var t = 1; } } } inner_var_if: { options = { evaluate: true, reduce_vars: true, } input: { function f(a){ if (a) var t = 1; if (!t) console.log(t); } } expect: { function f(a){ if (a) var t = 1; if (!t) console.log(t); } } } inner_var_label: { options = { evaluate: true, reduce_vars: true, } input: { function f(a){ l: { if (a) break l; var t = 1; } console.log(t); } } expect: { function f(a){ l: { if (a) break l; var t = 1; } console.log(t); } } } inner_var_for: { options = { evaluate: true, reduce_vars: true, } input: { function f() { var a = 1; x(a, b, d); for (var b = 2, c = 3; x(a, b, c, d); x(a, b, c, d)) { var d = 4, e = 5; x(a, b, c, d, e); } x(a, b, c, d, e); } } expect: { function f() { var a = 1; x(1, b, d); for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) { var d = 4, e = 5; x(1, b, 3, d, e); } x(1, b, 3, d, e); } } } inner_var_for_in_1: { options = { evaluate: true, reduce_vars: true, } input: { function f() { var a = 1, b = 2; for (b in (function() { return x(a, b, c); })()) { var c = 3, d = 4; x(a, b, c, d); } x(a, b, c, d); } } expect: { function f() { var a = 1, b = 2; for (b in (function() { return x(1, b, c); })()) { var c = 3, d = 4; x(1, b, c, d); } x(1, b, c, d); } } } inner_var_for_in_2: { options = { evaluate: true, reduce_vars: true, } input: { function f() { for (var long_name in {}) console.log(long_name); } } expect: { function f() { for (var long_name in {}) console.log(long_name); } } } inner_var_catch: { options = { evaluate: true, reduce_vars: true, } input: { function f() { try { a(); } catch (e) { var b = 1; } console.log(b); } } expect: { function f() { try { a(); } catch (e) { var b = 1; } console.log(b); } } } issue_1533_1: { options = { collapse_vars: true, reduce_vars: true, } input: { function f() { var id = ""; for (id in {break: "me"}) console.log(id); } } expect: { function f() { var id = ""; for (id in {break: "me"}) console.log(id); } } } issue_1533_2: { options = { evaluate: true, reduce_vars: true, } input: { function f() { var id = ""; for (var id in {break: "me"}) console.log(id); console.log(id); } } expect: { function f() { var id = ""; for (var id in {break: "me"}) console.log(id); console.log(id); } } } toplevel_on: { options = { evaluate: true, reduce_vars: true, toplevel:true, unused: true, } input: { var x = 3; console.log(x); } expect: { console.log(3); } expect_stdout: true } toplevel_off: { options = { evaluate: true, reduce_vars: true, toplevel:false, unused: true, } input: { var x = 3; console.log(x); } expect: { var x = 3; console.log(x); } expect_stdout: true } toplevel_on_loops_1: { options = { evaluate: true, loops: true, reduce_vars: true, toplevel:true, unused: true, } input: { function bar() { console.log("bar:", --x); } var x = 3; do bar(); while (x); } expect: { var x = 3; do (function() { console.log("bar:", --x); })(); while (x); } expect_stdout: true } toplevel_off_loops_1: { options = { evaluate: true, loops: true, reduce_vars: true, toplevel:false, unused: true, } input: { function bar() { console.log("bar:", --x); } var x = 3; do bar(); while (x); } expect: { function bar() { console.log("bar:", --x); } var x = 3; do bar(); while (x); } expect_stdout: true } toplevel_on_loops_2: { options = { evaluate: true, loops: true, reduce_vars: true, toplevel:true, unused: true, } input: { function bar() { console.log("bar:"); } var x = 3; do bar(); while (x); } expect: { for (;;) (function() { console.log("bar:"); })(); } } toplevel_off_loops_2: { options = { evaluate: true, loops: true, reduce_vars: true, toplevel:false, unused: true, } input: { function bar() { console.log("bar:"); } var x = 3; do bar(); while (x); } expect: { function bar() { console.log("bar:"); } var x = 3; do bar(); while (x); } } toplevel_on_loops_3: { options = { evaluate: true, loops: true, reduce_vars: true, toplevel:true, unused: true, } input: { var x = 3; while (x) bar(); } expect: { for (;;) bar(); } } toplevel_off_loops_3: { options = { evaluate: true, loops: true, reduce_vars: true, toplevel:false, unused: true, } input: { var x = 3; while (x) bar(); } expect: { var x = 3; for (;x;) bar(); } } defun_reference: { options = { evaluate: true, reduce_vars: true, } input: { function f() { function g() { x(); return a; } var a = h(); var b = 2; return a + b; function h() { y(); return b; } } } expect: { function f() { function g() { x(); return a; } var a = h(); var b = 2; return a + b; function h() { y(); return b; } } } } defun_inline_1: { options = { reduce_vars: true, unused: true, } input: { function f() { return g(2) + h(); function g(b) { return b; } function h() { return h(); } } } expect: { function f() { return function(b) { return b; }(2) + h(); function h() { return h(); } } } } defun_inline_2: { options = { reduce_vars: true, unused: true, } input: { function f() { function g(b) { return b; } function h() { return h(); } return g(2) + h(); } } expect: { function f() { function h() { return h(); } return function(b) { return b; }(2) + h(); } } } defun_inline_3: { options = { evaluate: true, passes: 2, reduce_vars: true, side_effects: true, unused: true, } input: { function f() { return g(2); function g(b) { return b; } } } expect: { function f() { return 2; } } } defun_call: { options = { reduce_vars: true, unused: true, } input: { function f() { return g() + h(1) - h(g(), 2, 3); function g() { return 4; } function h(a) { return a; } } } expect: { function f() { return 4 + h(1) - h(4); function h(a) { return a; } } } } defun_redefine: { options = { reduce_vars: true, unused: true, } input: { function f() { function g() { return 1; } function h() { return 2; } g = function() { return 3; }; return g() + h(); } } expect: { function f() { function g() { return 1; } g = function() { return 3; }; return g() + 2; } } } func_inline: { options = { reduce_vars: true, unused: true, } input: { function f() { var g = function() { return 1; }; console.log(g() + h()); var h = function() { return 2; }; } } expect: { function f() { console.log(1 + h()); var h = function() { return 2; }; } } } func_modified: { options = { reduce_vars: true, unused: true, } input: { function f(a) { function a() { return 1; } function b() { return 2; } function c() { return 3; } b.inject = []; c = function() { return 4; }; return a() + b() + c(); } } expect: { function f(a) { function b() { return 2; } function c() { return 3; } b.inject = []; c = function() { return 4; }; return 1 + 2 + c(); } } } defun_label: { options = { passes: 2, reduce_vars: true, unused: true, } input: { !function() { function f(a) { L: { if (a) break L; return 1; } } console.log(f(2)); }(); } expect: { !function() { console.log(function(a) { L: { if (a) break L; return 1; } }(2)); }(); } expect_stdout: true } double_reference: { options = { reduce_vars: true, unused: true, } input: { function f() { var g = function g() { g(); }; g(); } } expect: { function f() { (function g() { g(); })(); } } } iife_arguments_1: { options = { reduce_vars: true, unused: true, } input: { (function(x) { console.log(x() === arguments[0]); })(function f() { return f; }); } expect: { (function(x) { console.log(x() === arguments[0]); })(function f() { return f; }); } expect_stdout: true } iife_arguments_2: { options = { reduce_vars: true, unused: true, } input: { (function() { var x = function f() { return f; }; console.log(x() === arguments[0]); })(); } expect: { (function() { console.log(function f() { return f; }() === arguments[0]); })(); } expect_stdout: true } iife_eval_1: { options = { reduce_vars: true, unused: true, } input: { (function(x) { console.log(x() === eval("x")); })(function f() { return f; }); } expect: { (function(x) { console.log(x() === eval("x")); })(function f() { return f; }); } expect_stdout: true } iife_eval_2: { options = { reduce_vars: true, unused: true, } input: { (function() { var x = function f() { return f; }; console.log(x() === eval("x")); })(); } expect: { (function() { var x = function f() { return f; }; console.log(x() === eval("x")); })(); } expect_stdout: true } iife_func_side_effects: { options = { reduce_vars: true, unused: true, } input: { (function(a, b, c) { return b(); })(x(), function() { return y(); }, z()); } expect: { (function(a, b, c) { return function() { return y(); }(); })(x(), 0, z()); } } issue_1595_1: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { (function f(a) { return f(a + 1); })(2); } expect: { (function f(a) { return f(a + 1); })(2); } } issue_1595_2: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { (function f(a) { return g(a + 1); })(2); } expect: { (function(a) { return g(a + 1); })(2); } } issue_1595_3: { options = { evaluate: true, passes: 2, reduce_vars: true, unused: true, } input: { (function f(a) { return g(a + 1); })(2); } expect: { (function(a) { return g(3); })(); } } issue_1595_4: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { (function iife(a, b, c) { console.log(a, b, c); if (a) iife(a - 1, b, c); })(3, 4, 5); } expect: { (function iife(a, b, c) { console.log(a, b, c); if (a) iife(a - 1, b, c); })(3, 4, 5); } expect_stdout: true } issue_1606: { options = { evaluate: true, hoist_vars: true, reduce_vars: true, } input: { function f() { var a; function g(){}; var b = 2; x(b); } } expect: { function f() { var a, b; function g(){}; b = 2; x(b); } } } issue_1670_1: { options = { comparisons: true, conditionals: true, evaluate: true, dead_code: true, reduce_vars: true, side_effects: true, switches: true, unused: true, } input: { (function f() { switch (1) { case 0: var a = true; break; default: if (typeof a === "undefined") console.log("PASS"); else console.log("FAIL"); } })(); } expect: { (function() { var a; void 0 === a ? console.log("PASS") : console.log("FAIL"); })(); } expect_stdout: "PASS" } issue_1670_2: { options = { conditionals: true, evaluate: true, dead_code: true, passes: 2, reduce_vars: true, side_effects: true, switches: true, unused: true, } input: { (function f() { switch (1) { case 0: var a = true; break; default: if (typeof a === "undefined") console.log("PASS"); else console.log("FAIL"); } })(); } expect: { (function() { console.log("PASS"); })(); } expect_stdout: "PASS" } issue_1670_3: { options = { comparisons: true, conditionals: true, evaluate: true, dead_code: true, reduce_vars: true, side_effects: true, switches: true, unused: true, } input: { (function f() { switch (1) { case 0: var a = true; break; case 1: if (typeof a === "undefined") console.log("PASS"); else console.log("FAIL"); } })(); } expect: { (function() { var a; void 0 === a ? console.log("PASS") : console.log("FAIL"); })(); } expect_stdout: "PASS" } issue_1670_4: { options = { conditionals: true, evaluate: true, dead_code: true, passes: 2, reduce_vars: true, side_effects: true, switches: true, unused: true, } input: { (function f() { switch (1) { case 0: var a = true; break; case 1: if (typeof a === "undefined") console.log("PASS"); else console.log("FAIL"); } })(); } expect: { (function() { console.log("PASS"); })(); } expect_stdout: "PASS" } issue_1670_5: { options = { dead_code: true, evaluate: true, keep_fargs: false, reduce_vars: true, side_effects: true, switches: true, unused: true, } input: { (function(a) { switch (1) { case a: console.log(a); break; default: console.log(2); break; } })(1); } expect: { (function() { console.log(1); })(); } expect_stdout: "1" } issue_1670_6: { options = { dead_code: true, evaluate: true, keep_fargs: false, reduce_vars: true, side_effects: true, switches: true, unused: true, } input: { (function(a) { switch (1) { case a = 1: console.log(a); break; default: console.log(2); break; } })(1); } expect: { (function(a) { switch (1) { case a = 1: console.log(a); break; default: console.log(2); } })(1); } expect_stdout: "1" } unary_delete: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { var b = 10; function f() { var a; if (delete a) b--; } f(); console.log(b); } expect: { var b = 10; function f() { var a; if (delete a) b--; } f(); console.log(b); } expect_stdout: true } redefine_arguments_1: { options = { evaluate: true, keep_fargs: false, reduce_vars: true, unused: true, } input: { function f() { var arguments; return typeof arguments; } function g() { var arguments = 42; return typeof arguments; } function h(x) { var arguments = x; return typeof arguments; } console.log(f(), g(), h()); } expect: { function f() { var arguments; return typeof arguments; } function g() { return"number"; } function h(x) { var arguments = x; return typeof arguments; } console.log(f(), g(), h()); } expect_stdout: "object number undefined" } redefine_arguments_2: { options = { evaluate: true, keep_fargs: false, reduce_vars: true, side_effects: true, toplevel: true, unused: true, } input: { function f() { var arguments; return typeof arguments; } function g() { var arguments = 42; return typeof arguments; } function h(x) { var arguments = x; return typeof arguments; } console.log(f(), g(), h()); } expect: { console.log(function() { var arguments; return typeof arguments; }(), function() { return"number"; }(), function(x) { var arguments = x; return typeof arguments; }()); } expect_stdout: "object number undefined" } redefine_arguments_3: { options = { evaluate: true, keep_fargs: false, passes: 3, reduce_vars: true, side_effects: true, toplevel: true, unused: true, } input: { function f() { var arguments; return typeof arguments; } function g() { var arguments = 42; return typeof arguments; } function h(x) { var arguments = x; return typeof arguments; } console.log(f(), g(), h()); } expect: { console.log(function() { var arguments; return typeof arguments; }(), "number", function(x) { var arguments = x; return typeof arguments; }()); } expect_stdout: "object number undefined" } redefine_farg_1: { options = { evaluate: true, keep_fargs: false, reduce_vars: true, unused: true, } input: { function f(a) { var a; return typeof a; } function g(a) { var a = 42; return typeof a; } function h(a, b) { var a = b; return typeof a; } console.log(f([]), g([]), h([])); } expect: { function f(a) { var a; return typeof a; } function g() { return"number"; } function h(a, b) { var a = b; return typeof a; } console.log(f([]), g([]), h([])); } expect_stdout: "object number undefined" } redefine_farg_2: { options = { evaluate: true, keep_fargs: false, reduce_vars: true, side_effects: true, toplevel: true, unused: true, } input: { function f(a) { var a; return typeof a; } function g(a) { var a = 42; return typeof a; } function h(a, b) { var a = b; return typeof a; } console.log(f([]), g([]), h([])); } expect: { console.log(function(a) { var a; return typeof a; }([]), function() { return "number"; }(),function(a, b) { var a = b; return typeof a; }([])); } expect_stdout: "object number undefined" } redefine_farg_3: { options = { evaluate: true, keep_fargs: false, passes: 3, reduce_vars: true, side_effects: true, toplevel: true, unused: true, } input: { function f(a) { var a; return typeof a; } function g(a) { var a = 42; return typeof a; } function h(a, b) { var a = b; return typeof a; } console.log(f([]), g([]), h([])); } expect: { console.log(function(a) { var a; return typeof a; }([]), "number", function(a) { var a = void 0; return typeof a; }([])); } expect_stdout: "object number undefined" } delay_def: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { function f() { return a; var a; } function g() { return a; var a = 1; } console.log(f(), g()); } expect: { function f() { return a; var a; } function g() { return a; var a = 1; } console.log(f(), g()); } expect_stdout: true } booleans: { options = { booleans: true, evaluate: true, reduce_vars: true, } input: { console.log(function(a) { if (a != 0); switch (a) { case 0: return "FAIL"; case false: return "PASS"; } }(false)); } expect: { console.log(function(a) { if (!1); switch (!1) { case 0: return "FAIL"; case !1: return "PASS"; } }(!1)); } expect_stdout: "PASS" } side_effects_assign: { options = { evaluate: true, reduce_vars: true, sequences: true, side_effects: true, toplevel: true, } input: { var a = typeof void (a && a.in == 1, 0); console.log(a); } expect: { var a = typeof void (a && a.in); console.log(a); } expect_stdout: "undefined" } pure_getters_1: { options = { pure_getters: "strict", reduce_vars: true, side_effects: true, toplevel: true, } input: { try { var a = (a.b, 2); } catch (e) {} console.log(a); } expect: { try { var a = (a.b, 2); } catch (e) {} console.log(a); } expect_stdout: "undefined" } pure_getters_2: { options = { pure_getters: "strict", reduce_vars: true, toplevel: true, unused: true, } input: { var a; var a = a && a.b; } expect: { var a; var a = a && a.b; } } pure_getters_3: { options = { pure_getters: true, reduce_vars: true, toplevel: true, unused: true, } input: { var a; var a = a && a.b; } expect: { } } catch_var: { options = { booleans: true, evaluate: true, reduce_vars: true, } input: { try { throw {}; } catch (e) { var e; console.log(!!e); } } expect: { try { throw {}; } catch (e) { var e; console.log(!!e); } } expect_stdout: "true" } issue_1814_1: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { const a = 42; !function() { var b = a; !function(a) { console.log(a++, b); }(0); }(); } expect: { const a = 42; !function() { !function(a) { console.log(a++, 42); }(0); }(); } expect_stdout: "0 42" } issue_1814_2: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { const a = "32"; !function() { var b = a + 1; !function(a) { console.log(a++, b); }(0); }(); } expect: { const a = "32"; !function() { !function(a) { console.log(a++, "321"); }(0); }(); } expect_stdout: "0 '321'" } try_abort: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { !function() { try { var a = 1; throw ""; var b = 2; } catch (e) { } console.log(a, b); }(); } expect: { !function() { try { var a = 1; throw ""; var b = 2; } catch (e) { } console.log(a, b); }(); } expect_stdout: "1 undefined" } issue_1865: { options = { evaluate: true, reduce_vars: true, unsafe: true, } input: { function f(some) { some.thing = false; } console.log(function() { var some = { thing: true }; f(some); return some.thing; }()); } expect: { function f(some) { some.thing = false; } console.log(function() { var some = { thing: true }; f(some); return some.thing; }()); } expect_stdout: true } issue_1922_1: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { console.log(function(a) { arguments[0] = 2; return a; }(1)); } expect: { console.log(function(a) { arguments[0] = 2; return a; }(1)); } expect_stdout: "2" } issue_1922_2: { options = { evaluate: true, reduce_vars: true, unused: true, } input: { console.log(function() { var a; eval("a = 1"); return a; }(1)); } expect: { console.log(function() { var a; eval("a = 1"); return a; }(1)); } expect_stdout: "1" } accessor: { options = { evaluate: true, reduce_vars: true, toplevel: true, } input: { var a = 1; console.log({ get a() { a = 2; return a; }, b: 1 }.b, a); } expect: { var a = 1; console.log({ get a() { a = 2; return a; }, b: 1 }.b, a); } expect_stdout: "1 1" } UglifyJS2-2.8.29/test/compress/return_undefined.js000066400000000000000000000052621312030606600221040ustar00rootroot00000000000000return_undefined: { options = { sequences : false, if_return : true, evaluate : true, dead_code : true, conditionals : true, comparisons : true, booleans : true, unused : true, side_effects : true, properties : true, drop_debugger : true, loops : true, hoist_funs : true, keep_fargs : true, keep_fnames : false, hoist_vars : true, join_vars : true, cascade : true, negate_iife : true }; input: { function f0() { } function f1() { return undefined; } function f2() { return void 0; } function f3() { return void 123; } function f4() { return; } function f5(a, b) { console.log(a, b); baz(a); return; } function f6(a, b) { console.log(a, b); if (a) { foo(b); baz(a); return a + b; } return undefined; } function f7(a, b) { console.log(a, b); if (a) { foo(b); baz(a); return void 0; } return a + b; } function f8(a, b) { foo(a); bar(b); return void 0; } function f9(a, b) { foo(a); bar(b); return undefined; } function f10() { return false; } function f11() { return null; } function f12() { return 0; } } expect: { function f0() {} function f1() {} function f2() {} function f3() {} function f4() {} function f5(a, b) { console.log(a, b); baz(a); } function f6(a, b) { console.log(a, b); if (a) { foo(b); baz(a); return a + b; } } function f7(a, b) { console.log(a, b); if (!a) return a + b; foo(b); baz(a); } function f8(a, b) { foo(a); bar(b); } function f9(a, b) { foo(a); bar(b); } function f10() { return !1; } function f11() { return null; } function f12() { return 0; } } } UglifyJS2-2.8.29/test/compress/screw-ie8.js000066400000000000000000000110771312030606600203530ustar00rootroot00000000000000do_screw: { options = { screw_ie8: true, } beautify = { screw_ie8: true, ascii_only: true, } input: { f("\v"); } expect_exact: 'f("\\v");' } dont_screw: { options = { screw_ie8: false, } beautify = { screw_ie8: false, ascii_only: true, } input: { f("\v"); } expect_exact: 'f("\\x0B");' } do_screw_constants: { options = { screw_ie8: true, } input: { f(undefined, Infinity); } expect_exact: "f(void 0,1/0);" } dont_screw_constants: { options = { screw_ie8: false, } input: { f(undefined, Infinity); } expect_exact: "f(undefined,Infinity);" } do_screw_try_catch: { options = { screw_ie8: true }; mangle = { screw_ie8: true }; beautify = { screw_ie8: true }; input: { good = function(e){ return function(error){ try{ e() } catch(e) { error(e) } } }; } expect: { good = function(n){ return function(t){ try{ n() } catch(n) { t(n) } } }; } } dont_screw_try_catch: { options = { screw_ie8: false }; mangle = { screw_ie8: false }; beautify = { screw_ie8: false }; input: { bad = function(e){ return function(error){ try{ e() } catch(e) { error(e) } } }; } expect: { bad = function(n){ return function(t){ try{ n() } catch(n) { t(n) } } }; } } do_screw_try_catch_undefined: { options = { screw_ie8: true }; mangle = { screw_ie8: true }; beautify = { screw_ie8: true }; input: { function a(b){ try { throw 'Stuff'; } catch (undefined) { console.log('caught: ' + undefined); } console.log('undefined is ' + undefined); return b === undefined; }; } expect: { function a(o){ try{ throw "Stuff" } catch (o) { console.log("caught: "+o) } console.log("undefined is " + void 0); return void 0===o } } expect_stdout: true } dont_screw_try_catch_undefined: { options = { screw_ie8: false }; mangle = { screw_ie8: false }; beautify = { screw_ie8: false }; input: { function a(b){ try { throw 'Stuff'; } catch (undefined) { console.log('caught: ' + undefined); } console.log('undefined is ' + undefined); return b === undefined; }; } expect: { function a(n){ try{ throw "Stuff" } catch (undefined) { console.log("caught: " + undefined) } console.log("undefined is " + undefined); return n === undefined } } expect_stdout: true } reduce_vars: { options = { evaluate: true, reduce_vars: true, screw_ie8: false, unused: true, } mangle = { screw_ie8: false, } input: { function f() { var a; try { x(); } catch (a) { y(); } alert(a); } } expect: { function f() { var t; try { x(); } catch (t) { y(); } alert(t); } } } issue_1586_1: { options = { screw_ie8: false, } mangle = { screw_ie8: false, } input: { function f() { try { x(); } catch (err) { console.log(err.message); } } } expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}" } issue_1586_2: { options = { screw_ie8: true, } mangle = { screw_ie8: true, } input: { function f() { try { x(); } catch (err) { console.log(err.message); } } } expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}" } UglifyJS2-2.8.29/test/compress/sequences.js000066400000000000000000000302461312030606600205370ustar00rootroot00000000000000make_sequences_1: { options = { sequences: true }; input: { foo(); bar(); baz(); } expect: { foo(),bar(),baz(); } } make_sequences_2: { options = { sequences: true }; input: { if (boo) { foo(); bar(); baz(); } else { x(); y(); z(); } } expect: { if (boo) foo(),bar(),baz(); else x(),y(),z(); } } make_sequences_3: { options = { sequences: true }; input: { function f() { foo(); bar(); return baz(); } function g() { foo(); bar(); throw new Error(); } } expect: { function f() { return foo(), bar(), baz(); } function g() { throw foo(), bar(), new Error(); } } } make_sequences_4: { options = { sequences: true }; input: { x = 5; if (y) z(); x = 5; for (i = 0; i < 5; i++) console.log(i); x = 5; for (; i < 5; i++) console.log(i); x = 5; switch (y) {} x = 5; with (obj) {} } expect: { if (x = 5, y) z(); for (x = 5, i = 0; i < 5; i++) console.log(i); for (x = 5; i < 5; i++) console.log(i); switch (x = 5, y) {} with (x = 5, obj); } expect_stdout: true } lift_sequences_1: { options = { sequences: true }; input: { var foo, x, y, bar; foo = !(x(), y(), bar()); } expect: { var foo, x, y, bar; x(), y(), foo = !bar(); } } lift_sequences_2: { options = { sequences: true, evaluate: true }; input: { var foo = 1, bar; foo.x = (foo = {}, 10); bar = (bar = {}, 10); console.log(foo, bar); } expect: { var foo = 1, bar; foo.x = (foo = {}, 10), bar = {}, bar = 10, console.log(foo, bar); } expect_stdout: true } lift_sequences_3: { options = { sequences: true, conditionals: true }; input: { var x, foo, bar, baz; x = (foo(), bar(), baz()) ? 10 : 20; } expect: { var x, foo, bar, baz; foo(), bar(), x = baz() ? 10 : 20; } } lift_sequences_4: { options = { side_effects: true }; input: { var x, foo, bar, baz; x = (foo, bar, baz); } expect: { var x, foo, bar, baz; x = baz; } } lift_sequences_5: { options = { sequences: true, } input: { var a = 2, b; a *= (b, a = 4, 3); console.log(a); } expect: { var a = 2, b; b, a *= (a = 4, 3), console.log(a); } expect_stdout: "6" } for_sequences: { options = { sequences: true }; input: { // 1 foo(); bar(); for (; false;); // 2 foo(); bar(); for (x = 5; false;); // 3 x = (foo in bar); for (; false;); // 4 x = (foo in bar); for (y = 5; false;); } expect: { // 1 for (foo(), bar(); false;); // 2 for (foo(), bar(), x = 5; false;); // 3 x = (foo in bar); for (; false;); // 4 x = (foo in bar); for (y = 5; false;); } } limit_1: { options = { sequences: 3, }; input: { a; b; c; d; e; f; g; h; i; j; k; } expect: { a, b, c; d, e, f; g, h, i; j, k; } } limit_2: { options = { sequences: 3, }; input: { a, b; c, d; e, f; g, h; i, j; k; } expect: { a, b, c, d; e, f, g, h; i, j, k; } } negate_iife_for: { options = { sequences: true, negate_iife: true, }; input: { (function() {})(); for (i = 0; i < 5; i++) console.log(i); (function() {})(); for (; i < 5; i++) console.log(i); } expect: { for (!function() {}(), i = 0; i < 5; i++) console.log(i); for (function() {}(); i < 5; i++) console.log(i); } expect_stdout: true } iife: { options = { sequences: true, }; input: { x = 42; (function a() {})(); !function b() {}(); ~function c() {}(); +function d() {}(); -function e() {}(); void function f() {}(); typeof function g() {}(); } expect: { x = 42, function a() {}(), function b() {}(), function c() {}(), function d() {}(), function e() {}(), function f() {}(), function g() {}(); } } unsafe_undefined: { options = { conditionals: true, if_return: true, sequences: true, side_effects: true, unsafe: true, } input: { function f(undefined) { if (a) return b; if (c) return d; } function g(undefined) { if (a) return b; if (c) return d; e(); } } expect: { function f(undefined) { return a ? b : c ? d : undefined; } function g(undefined) { return a ? b : c ? d : void e(); } } } issue_1685: { options = { cascade: true, side_effects: true, } input: { var a = 100, b = 10; function f() { var a = (a--, delete a && --b); } f(); console.log(a, b); } expect: { var a = 100, b = 10; function f() { var a = (a--, delete a && --b); } f(); console.log(a, b); } expect_stdout: true } func_def_1: { options = { cascade: true, side_effects: true, } input: { function f() { return f = 0, !!f; } console.log(f()); } expect: { function f() { return !!(f = 0); } console.log(f()); } expect_stdout: "false" } func_def_2: { options = { cascade: true, side_effects: true, } input: { console.log(function f() { return f = 0, !!f; }()); } expect: { console.log(function f() { return f = 0, !!f; }()); } expect_stdout: "true" } func_def_3: { options = { cascade: true, side_effects: true, } input: { function f() { function g() {} return g = 0, !!g; } console.log(f()); } expect: { function f() { function g() {} return !!(g = 0); } console.log(f()); } expect_stdout: "false" } func_def_4: { options = { cascade: true, side_effects: true, } input: { function f() { function g() { return g = 0, !!g; } return g(); } console.log(f()); } expect: { function f() { function g() { return !!(g = 0); } return g(); } console.log(f()); } expect_stdout: "false" } func_def_5: { options = { cascade: true, side_effects: true, } input: { function f() { return function g(){ return g = 0, !!g; }(); } console.log(f()); } expect: { function f() { return function g(){ return g = 0, !!g; }(); } console.log(f()); } expect_stdout: "true" } issue_1758: { options = { sequences: true, side_effects: true, } input: { console.log(function(c) { var undefined = 42; return function() { c--; c--, c.toString(); return; }(); }()); } expect: { console.log(function(c) { var undefined = 42; return function() { return c--, c--, c.toString(), void 0; }(); }()); } expect_stdout: "undefined" } delete_seq_1: { options = { booleans: true, side_effects: true, } input: { console.log(delete (1, undefined)); console.log(delete (1, void 0)); console.log(delete (1, Infinity)); console.log(delete (1, 1 / 0)); console.log(delete (1, NaN)); console.log(delete (1, 0 / 0)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((1 / 0, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((0 / 0, !0)); } expect_stdout: true } delete_seq_2: { options = { booleans: true, side_effects: true, } input: { console.log(delete (1, 2, undefined)); console.log(delete (1, 2, void 0)); console.log(delete (1, 2, Infinity)); console.log(delete (1, 2, 1 / 0)); console.log(delete (1, 2, NaN)); console.log(delete (1, 2, 0 / 0)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((1 / 0, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((0 / 0, !0)); } expect_stdout: true } delete_seq_3: { options = { booleans: true, keep_infinity: true, side_effects: true, } input: { console.log(delete (1, 2, undefined)); console.log(delete (1, 2, void 0)); console.log(delete (1, 2, Infinity)); console.log(delete (1, 2, 1 / 0)); console.log(delete (1, 2, NaN)); console.log(delete (1, 2, 0 / 0)); } expect: { console.log((void 0, !0)); console.log((void 0, !0)); console.log((Infinity, !0)); console.log((1 / 0, !0)); console.log((NaN, !0)); console.log((0 / 0, !0)); } expect_stdout: true } delete_seq_4: { options = { booleans: true, sequences: true, side_effects: true, } input: { function f() {} console.log(delete (f(), undefined)); console.log(delete (f(), void 0)); console.log(delete (f(), Infinity)); console.log(delete (f(), 1 / 0)); console.log(delete (f(), NaN)); console.log(delete (f(), 0 / 0)); } expect: { function f() {} console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)); } expect_stdout: true } delete_seq_5: { options = { booleans: true, keep_infinity: true, sequences: true, side_effects: true, } input: { function f() {} console.log(delete (f(), undefined)); console.log(delete (f(), void 0)); console.log(delete (f(), Infinity)); console.log(delete (f(), 1 / 0)); console.log(delete (f(), NaN)); console.log(delete (f(), 0 / 0)); } expect: { function f() {} console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)), console.log((f(), !0)); } expect_stdout: true } delete_seq_6: { options = { booleans: true, side_effects: true, } input: { var a; console.log(delete (1, a)); } expect: { var a; console.log((a, !0)); } expect_stdout: true } reassign_const: { options = { cascade: true, sequences: true, side_effects: true, } input: { function f() { const a = 1; a++; return a; } console.log(f()); } expect: { function f() { const a = 1; return a++, a; } console.log(f()); } expect_stdout: true } UglifyJS2-2.8.29/test/compress/string-literal.js000066400000000000000000000004641312030606600215030ustar00rootroot00000000000000octal_escape_sequence: { input: { var boundaries = "\0\7\00\07\70\77\000\077\300\377"; var border_check = "\400\700\0000\3000"; } expect: { var boundaries = "\x00\x07\x00\x07\x38\x3f\x00\x3f\xc0\xff"; var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30"; } } UglifyJS2-2.8.29/test/compress/switch.js000066400000000000000000000341061312030606600200440ustar00rootroot00000000000000constant_switch_1: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { switch (1+1) { case 1: foo(); break; case 1+1: bar(); break; case 1+1+1: baz(); break; } } expect: { bar(); } } constant_switch_2: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { switch (1) { case 1: foo(); case 1+1: bar(); break; case 1+1+1: baz(); } } expect: { foo(); bar(); } } constant_switch_3: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { switch (10) { case 1: foo(); case 1+1: bar(); break; case 1+1+1: baz(); default: def(); } } expect: { def(); } } constant_switch_4: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { switch (2) { case 1: x(); if (foo) break; y(); break; case 1+1: bar(); default: def(); } } expect: { bar(); def(); } } constant_switch_5: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { switch (1) { case 1: x(); if (foo) break; y(); break; case 1+1: bar(); default: def(); } } expect: { // the break inside the if ruins our job // we can still get rid of irrelevant cases. switch (1) { case 1: x(); if (foo) break; y(); } // XXX: we could optimize this better by inventing an outer // labeled block, but that's kinda tricky. } } constant_switch_6: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { OUT: { foo(); switch (1) { case 1: x(); if (foo) break OUT; y(); case 1+1: bar(); break; default: def(); } } } expect: { OUT: { foo(); x(); if (foo) break OUT; y(); bar(); } } } constant_switch_7: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { OUT: { foo(); switch (1) { case 1: x(); if (foo) break OUT; for (var x = 0; x < 10; x++) { if (x > 5) break; // this break refers to the for, not to the switch; thus it // shouldn't ruin our optimization console.log(x); } y(); case 1+1: bar(); break; default: def(); } } } expect: { OUT: { foo(); x(); if (foo) break OUT; for (var x = 0; x < 10; x++) { if (x > 5) break; console.log(x); } y(); bar(); } } } constant_switch_8: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { OUT: switch (1) { case 1: x(); for (;;) break OUT; y(); break; case 1+1: bar(); default: def(); } } expect: { OUT: { x(); for (;;) break OUT; y(); } } } constant_switch_9: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { OUT: switch (1) { case 1: x(); for (;;) if (foo) break OUT; y(); case 1+1: bar(); default: def(); } } expect: { OUT: { x(); for (;;) if (foo) break OUT; y(); bar(); def(); } } } drop_default_1: { options = { dead_code: true, switches: true, } input: { switch (foo) { case 'bar': baz(); default: } } expect: { switch (foo) { case 'bar': baz(); } } } drop_default_2: { options = { dead_code: true, switches: true, } input: { switch (foo) { case 'bar': baz(); break; default: break; } } expect: { switch (foo) { case 'bar': baz(); } } } keep_default: { options = { dead_code: true, switches: true, } input: { switch (foo) { case 'bar': baz(); default: something(); break; } } expect: { switch (foo) { case 'bar': baz(); default: something(); } } } issue_1663: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { var a = 100, b = 10; function f() { switch (1) { case 1: b = a++; return ++b; default: var b; } } f(); console.log(a, b); } expect: { var a = 100, b = 10; function f() { var b; b = a++; return ++b; } f(); console.log(a, b); } expect_stdout: true } drop_case: { options = { dead_code: true, switches: true, } input: { switch (foo) { case 'bar': baz(); break; case 'moo': break; } } expect: { switch (foo) { case 'bar': baz(); } } } keep_case: { options = { dead_code: true, switches: true, } input: { switch (foo) { case 'bar': baz(); break; case moo: break; } } expect: { switch (foo) { case 'bar': baz(); break; case moo: } } } issue_376: { options = { dead_code: true, evaluate: true, switches: true, } input: { switch (true) { case boolCondition: console.log(1); break; case false: console.log(2); break; } } expect: { switch (true) { case boolCondition: console.log(1); } } } issue_441_1: { options = { dead_code: true, switches: true, } input: { switch (foo) { case bar: qux(); break; case baz: qux(); break; default: qux(); break; } } expect: { switch (foo) { case bar: case baz: default: qux(); } } } issue_441_2: { options = { dead_code: true, switches: true, } input: { switch (foo) { case bar: // TODO: Fold into the case below qux(); break; case fall: case baz: qux(); break; default: qux(); break; } } expect: { switch (foo) { case bar: qux(); break; case fall: case baz: default: qux(); } } } issue_1674: { options = { dead_code: true, evaluate: true, side_effects: true, switches: true, } input: { switch (0) { default: console.log("FAIL"); break; case 0: console.log("PASS"); break; } } expect: { console.log("PASS"); } expect_stdout: "PASS" } issue_1679: { options = { dead_code: true, evaluate: true, switches: true, } input: { var a = 100, b = 10; function f() { switch (--b) { default: case !function x() {}: break; case b--: switch (0) { default: case a--: } break; case (a++): break; } } f(); console.log(a, b); } expect: { var a = 100, b = 10; function f() { switch (--b) { default: case !function x() {}: break; case b--: switch (0) { default: case a--: } break; case (a++): } } f(); console.log(a, b); } expect_stdout: true } issue_1680_1: { options = { dead_code: true, evaluate: true, switches: true, } input: { function f(x) { console.log(x); return x + 1; } switch (2) { case f(0): case f(1): f(2); case 2: case f(3): case f(4): f(5); } } expect: { function f(x) { console.log(x); return x + 1; } switch (2) { case f(0): case f(1): f(2); case 2: f(5); } } expect_stdout: [ "0", "1", "2", "5", ] } issue_1680_2: { options = { dead_code: true, switches: true, } input: { var a = 100, b = 10; switch (b) { case a--: break; case b: var c; break; case a: break; case a--: break; } console.log(a, b); } expect: { var a = 100, b = 10; switch (b) { case a--: break; case b: var c; break; case a: case a--: } console.log(a, b); } expect_stdout: true } issue_1690_1: { options = { dead_code: true, switches: true, } input: { switch (console.log("PASS")) {} } expect: { console.log("PASS"); } expect_stdout: "PASS" } issue_1690_2: { options = { dead_code: false, switches: true, } input: { switch (console.log("PASS")) {} } expect: { switch (console.log("PASS")) {} } expect_stdout: "PASS" } if_switch_typeof: { options = { conditionals: true, dead_code: true, side_effects: true, switches: true, } input: { if (a) switch(typeof b) {} } expect: { a; } } issue_1698: { options = { side_effects: true, switches: true, } input: { var a = 1; !function() { switch (a++) {} }(); console.log(a); } expect: { var a = 1; !function() { switch (a++) {} }(); console.log(a); } expect_stdout: "2" } issue_1705_1: { options = { dead_code: true, switches: true, } input: { var a = 0; switch (a) { default: console.log("FAIL"); case 0: break; } } expect: { var a = 0; switch (a) { default: console.log("FAIL"); case 0: } } expect_stdout: true } issue_1705_2: { options = { dead_code: true, evaluate: true, reduce_vars: true, sequences: true, side_effects: true, switches: true, toplevel: true, unused: true, } input: { var a = 0; switch (a) { default: console.log("FAIL"); case 0: break; } } expect: { } expect_stdout: true } issue_1705_3: { options = { dead_code: true, switches: true, } input: { switch (a) { case 0: break; default: break; } } expect: { a; } expect_stdout: true } beautify: { beautify = { beautify: true, } input: { switch (a) { case 0: case 1: break; case 2: default: } switch (b) { case 3: foo(); bar(); default: break; } } expect_exact: [ "switch (a) {", " case 0:", " case 1:", " break;", "", " case 2:", " default:", "}", "", "switch (b) {", " case 3:", " foo();", " bar();", "", " default:", " break;", "}", ] } issue_1758: { options = { dead_code: true, switches: true, } input: { var a = 1, b = 2; switch (a--) { default: b++; } console.log(a, b); } expect: { var a = 1, b = 2; a--; b++; console.log(a, b); } expect_stdout: "0 3" } UglifyJS2-2.8.29/test/compress/transform.js000066400000000000000000000043671312030606600205640ustar00rootroot00000000000000booleans_evaluate: { options = { booleans: true, evaluate: true, } input: { console.log(typeof void 0 != "undefined"); console.log(1 == 1, 1 === 1) console.log(1 != 1, 1 !== 1) } expect: { console.log(!1); console.log(!0, !0); console.log(!1, !1); } expect_stdout: true } booleans_global_defs: { options = { booleans: true, evaluate: true, global_defs: { A: true, }, } input: { console.log(A == 1); } expect: { console.log(!0); } } condition_evaluate: { options = { booleans: true, dead_code: false, evaluate: true, loops: false, } input: { while (1 === 2); for (; 1 == true;); if (void 0 == null); } expect: { while (!1); for (; !0;); if (!0); } } if_else_empty: { options = { conditionals: true, } input: { if ({} ? a : b); else {} } expect: { !{} ? b : a; } } label_if_break: { options = { conditionals: true, dead_code: true, evaluate: true, } input: { L: if (true) { a; break L; } } expect: { a; } } while_if_break: { options = { conditionals: true, loops: true, sequences: true, } input: { while (a) { if (b) if(c) d; if (e) break; } } expect: { for(; a && (b && c && d, !e);); } } if_return: { options = { booleans: true, conditionals: true, if_return: true, sequences: true, } input: { function f(w, x, y, z) { if (x) return; if (w) { if (y) return; } else if (z) return; if (x == y) return true; if (x) w(); if (y) z(); return true; } } expect: { function f(w, x, y, z) { if (!x) { if (w) { if (y) return; } else if (z) return; return x == y || (x && w(), y && z(), !0); } } } } UglifyJS2-2.8.29/test/compress/typeof.js000066400000000000000000000023711312030606600200500ustar00rootroot00000000000000typeof_evaluation: { options = { evaluate: true }; input: { a = typeof 1; b = typeof 'test'; c = typeof []; d = typeof {}; e = typeof /./; f = typeof false; g = typeof function(){}; h = typeof undefined; } expect: { a='number'; b='string'; c=typeof[]; d=typeof{}; e=typeof/./; f='boolean'; g='function'; h='undefined'; } } typeof_in_boolean_context: { options = { booleans : true, evaluate : true, conditionals : true, side_effects : true, }; input: { function f1(x) { return typeof x ? "yes" : "no"; } function f2() { return typeof g()? "Yes" : "No"; } typeof 0 ? foo() : bar(); !typeof console.log(1); var a = !typeof console.log(2); if (typeof (1 + foo())); } expect: { function f1(x) { return "yes"; } function f2() { return g(), "Yes"; } foo(); console.log(1); var a = !(console.log(2), !0); foo(); } } issue_1668: { options = { booleans: true, } input: { if (typeof bar); } expect: { if (!0); } } UglifyJS2-2.8.29/test/compress/unicode.js000066400000000000000000000004631312030606600201700ustar00rootroot00000000000000unicode_parse_variables: { options = {}; input: { var a = {}; a.你好 = 456; var ↂωↂ = 123; var l০ = 3; // 2nd char is a unicode digit } expect: { var a = {}; a.你好 = 456; var ↂωↂ = 123; var l০ = 3; } } UglifyJS2-2.8.29/test/compress/wrap_iife.js000066400000000000000000000016731312030606600205130ustar00rootroot00000000000000wrap_iife: { options = { negate_iife: false, } beautify = { wrap_iife: true, } input: { (function() { return function() { console.log('test') }; })()(); } expect_exact: '(function(){return function(){console.log("test")}})()();' } wrap_iife_in_expression: { options = { negate_iife: false, } beautify = { wrap_iife: true, } input: { foo = (function () { return bar(); })(); } expect_exact: 'foo=(function(){return bar()})();' } wrap_iife_in_return_call: { options = { negate_iife: false, } beautify = { wrap_iife: true, } input: { (function() { return (function() { console.log('test') })(); })()(); } expect_exact: '(function(){return(function(){console.log("test")})()})()();' } UglifyJS2-2.8.29/test/input/000077500000000000000000000000001312030606600155055ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/comments/000077500000000000000000000000001312030606600173325ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/comments/filter.js000066400000000000000000000000341312030606600211520ustar00rootroot00000000000000// foo /*@preserve*/ // bar UglifyJS2-2.8.29/test/input/global_defs/000077500000000000000000000000001312030606600177465ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/global_defs/nested.js000066400000000000000000000000271312030606600215650ustar00rootroot00000000000000console.log(C.V, C.D); UglifyJS2-2.8.29/test/input/global_defs/simple.js000066400000000000000000000000201312030606600215650ustar00rootroot00000000000000console.log(D); UglifyJS2-2.8.29/test/input/invalid/000077500000000000000000000000001312030606600171335ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/invalid/assign_1.js000066400000000000000000000000271312030606600211740ustar00rootroot00000000000000console.log(1 || 5--); UglifyJS2-2.8.29/test/input/invalid/assign_2.js000066400000000000000000000000501312030606600211710ustar00rootroot00000000000000console.log(2 || (Math.random() /= 2)); UglifyJS2-2.8.29/test/input/invalid/assign_3.js000066400000000000000000000000321312030606600211720ustar00rootroot00000000000000console.log(3 || ++this); UglifyJS2-2.8.29/test/input/invalid/assign_4.js000066400000000000000000000000071312030606600211750ustar00rootroot00000000000000++null UglifyJS2-2.8.29/test/input/invalid/dot_1.js000066400000000000000000000000041312030606600204710ustar00rootroot00000000000000a.= UglifyJS2-2.8.29/test/input/invalid/dot_2.js000066400000000000000000000000051312030606600204730ustar00rootroot00000000000000%.a; UglifyJS2-2.8.29/test/input/invalid/dot_3.js000066400000000000000000000000071312030606600204760ustar00rootroot00000000000000a./(); UglifyJS2-2.8.29/test/input/invalid/else.js000066400000000000000000000000171312030606600204170ustar00rootroot00000000000000if (0) else 1; UglifyJS2-2.8.29/test/input/invalid/eof.js000066400000000000000000000000121312030606600202330ustar00rootroot00000000000000foo, bar( UglifyJS2-2.8.29/test/input/invalid/loop-no-body.js000066400000000000000000000000351312030606600220050ustar00rootroot00000000000000for (var i = 0; i < 1; i++) UglifyJS2-2.8.29/test/input/invalid/object.js000066400000000000000000000000251312030606600207340ustar00rootroot00000000000000console.log({%: 1}); UglifyJS2-2.8.29/test/input/invalid/return.js000066400000000000000000000000131312030606600210020ustar00rootroot00000000000000return 42; UglifyJS2-2.8.29/test/input/invalid/simple.js000066400000000000000000000000171312030606600207600ustar00rootroot00000000000000function f(a{} UglifyJS2-2.8.29/test/input/invalid/tab.js000066400000000000000000000000231312030606600202320ustar00rootroot00000000000000 foo( xyz, 0abc); UglifyJS2-2.8.29/test/input/issue-1236/000077500000000000000000000000001312030606600172265ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-1236/simple.js000066400000000000000000000002001312030606600210450ustar00rootroot00000000000000"use strict"; var foo = function foo(x) { return "foo " + x; }; console.log(foo("bar")); //# sourceMappingURL=simple.js.map UglifyJS2-2.8.29/test/input/issue-1236/simple.js.map000066400000000000000000000004371312030606600216350ustar00rootroot00000000000000{ "version": 3, "sources": ["index.js"], "names": [], "mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ", "file": "simple.js", "sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"] } UglifyJS2-2.8.29/test/input/issue-1242/000077500000000000000000000000001312030606600172235ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-1242/bar.es5000066400000000000000000000001051312030606600204010ustar00rootroot00000000000000function bar(x) { var triple = x * (2 + 1); return triple; } UglifyJS2-2.8.29/test/input/issue-1242/baz.es5000066400000000000000000000000731312030606600204150ustar00rootroot00000000000000function baz(x) { var half = x / 2; return half; } UglifyJS2-2.8.29/test/input/issue-1242/foo.es5000066400000000000000000000001541312030606600204240ustar00rootroot00000000000000var print = console.log.bind(console); function foo(x) { var twice = x * 2; print('Foo:', twice); } UglifyJS2-2.8.29/test/input/issue-1242/qux.js000066400000000000000000000001141312030606600203720ustar00rootroot00000000000000var a = bar(1+2); var b = baz(3+9); print('q' + 'u' + 'x', a, b); foo(5+6); UglifyJS2-2.8.29/test/input/issue-1323/000077500000000000000000000000001312030606600172235ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-1323/sample.js000066400000000000000000000001421312030606600210370ustar00rootroot00000000000000var bar = (function () { function foo (bar) { return bar; } return foo; })();UglifyJS2-2.8.29/test/input/issue-1431/000077500000000000000000000000001312030606600172235ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-1431/sample.js000066400000000000000000000003121312030606600210360ustar00rootroot00000000000000function f(x) { return function() { function n(a) { return a * a; } return x(n); }; } function g(op) { return op(1) + op(2); } console.log(f(g)() == 5);UglifyJS2-2.8.29/test/input/issue-1482/000077500000000000000000000000001312030606600172315ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-1482/bracketize.js000066400000000000000000000014361312030606600217160ustar00rootroot00000000000000if (x) { foo(); } if (x) { foo(); } else { baz(); } if (x) { foo(); } else if (y) { bar(); } else { baz(); } if (x) { if (y) { foo(); } else { bar(); } } else { baz(); } if (x) { foo(); } else if (y) { bar(); } else if (z) { baz(); } else { moo(); } function f() { if (x) { foo(); } if (x) { foo(); } else { baz(); } if (x) { foo(); } else if (y) { bar(); } else { baz(); } if (x) { if (y) { foo(); } else { bar(); } } else { baz(); } if (x) { foo(); } else if (y) { bar(); } else if (z) { baz(); } else { moo(); } } UglifyJS2-2.8.29/test/input/issue-1482/default.js000066400000000000000000000006561312030606600212220ustar00rootroot00000000000000if (x) foo(); if (x) foo(); else baz(); if (x) foo(); else if (y) bar(); else baz(); if (x) if (y) foo(); else bar(); else baz(); if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); function f() { if (x) foo(); if (x) foo(); else baz(); if (x) foo(); else if (y) bar(); else baz(); if (x) if (y) foo(); else bar(); else baz(); if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); } UglifyJS2-2.8.29/test/input/issue-1482/input.js000066400000000000000000000006251312030606600207310ustar00rootroot00000000000000if (x) foo(); if (x) foo(); else baz(); if (x) foo(); else if (y) bar(); else baz(); if (x) if (y) foo(); else bar(); else baz(); if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); function f() { if (x) foo(); if (x) foo(); else baz(); if (x) foo(); else if (y) bar(); else baz(); if (x) if (y) foo(); else bar(); else baz(); if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); } UglifyJS2-2.8.29/test/input/issue-1632/000077500000000000000000000000001312030606600172265ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-1632/^{foo}[bar](baz)+$.js000066400000000000000000000000171312030606600230050ustar00rootroot00000000000000console.log(x);UglifyJS2-2.8.29/test/input/issue-520/000077500000000000000000000000001312030606600171415ustar00rootroot00000000000000UglifyJS2-2.8.29/test/input/issue-520/input.js000066400000000000000000000007521312030606600206420ustar00rootroot00000000000000var Foo = function Foo(){console.log(1+2);}; new Foo(); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQU0sR0FBRyxHQUFDLEFBQUUsWUFBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBLEFBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDOyJ9 UglifyJS2-2.8.29/test/input/issue-520/output.js000066400000000000000000000005251312030606600210410ustar00rootroot00000000000000new function(){console.log(3)}; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxHQUFyQyxZQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19 UglifyJS2-2.8.29/test/jetstream.js000066400000000000000000000060761312030606600167130ustar00rootroot00000000000000#! /usr/bin/env node // -*- js -*- "use strict"; var site = "http://browserbench.org/JetStream/"; if (typeof phantom == "undefined") { // workaround for tty output truncation upon process.exit() [process.stdout, process.stderr].forEach(function(stream){ if (stream._handle && stream._handle.setBlocking) stream._handle.setBlocking(true); }); var args = process.argv.slice(2); if (!args.length) { args.push("-mc", "warnings=false"); } args.push("--stats"); var child_process = require("child_process"); try { require("phantomjs-prebuilt"); } catch(e) { child_process.execSync("npm install phantomjs-prebuilt@2.1.14"); } var http = require("http"); var server = http.createServer(function(request, response) { request.resume(); var url = decodeURIComponent(request.url.slice(1)); var stderr = ""; var uglifyjs = child_process.fork("bin/uglifyjs", args, { silent: true }).on("exit", function(code) { console.log("uglifyjs", url.indexOf(site) == 0 ? url.slice(site.length) : url, args.join(" ")); console.log(stderr); if (code) throw new Error("uglifyjs failed with code " + code); }); uglifyjs.stderr.on("data", function(data) { stderr += data; }).setEncoding("utf8"); uglifyjs.stdout.pipe(response); http.get(url, function(res) { res.pipe(uglifyjs.stdin); }); }).listen().on("listening", function() { var phantomjs = require("phantomjs-prebuilt"); var program = phantomjs.exec(process.argv[1], server.address().port); program.stdout.pipe(process.stdout); program.stderr.pipe(process.stderr); program.on("exit", function(code) { server.close(); if (code) throw new Error("JetStream failed!"); console.log("JetStream completed successfully."); }); }); server.timeout = 0; } else { var page = require("webpage").create(); page.onError = function(msg, trace) { var body = [ msg ]; if (trace) trace.forEach(function(t) { body.push(" " + (t.function || "Anonymous function") + " (" + t.file + ":" + t.line + ")"); }); console.error(body.join("\n")); phantom.exit(1); }; var url = "http://localhost:" + require("system").args[1] + "/"; page.onResourceRequested = function(requestData, networkRequest) { if (/\.js$/.test(requestData.url)) networkRequest.changeUrl(url + encodeURIComponent(requestData.url)); } page.onConsoleMessage = function(msg) { if (/Error:/i.test(msg)) { console.error(msg); phantom.exit(1); } console.log(msg); if (~msg.indexOf("Raw results:")) { phantom.exit(); } }; page.open(site, function(status) { if (status != "success") phantomjs.exit(1); page.evaluate(function() { JetStream.switchToQuick(); JetStream.start(); }); }); } UglifyJS2-2.8.29/test/mocha.js000066400000000000000000000012111312030606600157660ustar00rootroot00000000000000var Mocha = require('mocha'), fs = require('fs'), path = require('path'); // Instantiate a Mocha instance. var mocha = new Mocha({}); var testDir = __dirname + '/mocha/'; // Add each .js file to the mocha instance fs.readdirSync(testDir).filter(function(file){ // Only keep the .js files return file.substr(-3) === '.js'; }).forEach(function(file){ mocha.addFile( path.join(testDir, file) ); }); module.exports = function() { mocha.run(function(failures) { if (failures !== 0) { process.on('exit', function () { process.exit(failures); }); } }); };UglifyJS2-2.8.29/test/mocha/000077500000000000000000000000001312030606600154355ustar00rootroot00000000000000UglifyJS2-2.8.29/test/mocha/accessorTokens-1492.js000066400000000000000000000025131312030606600213570ustar00rootroot00000000000000var UglifyJS = require('../../'); var assert = require("assert"); describe("Accessor tokens", function() { it("Should fill the token information for accessors (issue #1492)", function() { // location 0 1 2 3 4 // 01234567890123456789012345678901234567890123456789 var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }"); // test all AST_ObjectProperty tokens are set as expected var checkedAST_ObjectProperty = false; var checkWalker = new UglifyJS.TreeWalker(function(node, descend) { if (node instanceof UglifyJS.AST_ObjectProperty) { checkedAST_ObjectProperty = true; assert.equal(node.start.pos, 12); assert.equal(node.end.endpos, 46); assert(node.key instanceof UglifyJS.AST_SymbolAccessor); assert.equal(node.key.start.pos, 16); assert.equal(node.key.end.endpos, 22); assert(node.value instanceof UglifyJS.AST_Accessor); assert.equal(node.value.start.pos, 22); assert.equal(node.value.end.endpos, 46); } }); ast.walk(checkWalker); assert(checkedAST_ObjectProperty, "AST_ObjectProperty not found"); }); });UglifyJS2-2.8.29/test/mocha/arguments.js000066400000000000000000000024141312030606600200010ustar00rootroot00000000000000var UglifyJS = require('../../'); var assert = require("assert"); describe("arguments", function() { it("Should known that arguments in functions are local scoped", function() { var ast = UglifyJS.parse("var arguments; var f = function() {arguments.length}"); ast.figure_out_scope(); // Test scope of `var arguments` assert.strictEqual(ast.find_variable("arguments").global, true); // Select arguments symbol in function var symbol = ast.body[1].definitions[0].value.find_variable("arguments"); assert.strictEqual(symbol.global, false); assert.strictEqual(symbol.scope, ast. // From ast body[1]. // Select 2nd statement (equals to `var f ...`) definitions[0]. // First definition of selected statement value // Select function as scope ); }); it("Should recognize when a function uses arguments", function() { var ast = UglifyJS.parse("function a(){function b(){function c(){}; return arguments[0];}}"); ast.figure_out_scope(); assert.strictEqual(ast.body[0].uses_arguments, false); assert.strictEqual(ast.body[0].body[0].uses_arguments, true); assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false); }); });UglifyJS2-2.8.29/test/mocha/cli.js000066400000000000000000000413721312030606600165510ustar00rootroot00000000000000var assert = require("assert"); var exec = require("child_process").exec; var readFileSync = require("fs").readFileSync; describe("bin/uglifyjs", function () { var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs'; it("should produce a functional build when using --self", function (done) { this.timeout(15000); var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS'; exec(command, function (err, stdout) { if (err) throw err; eval(stdout); assert.strictEqual(typeof WrappedUglifyJS, 'object'); assert.strictEqual(true, WrappedUglifyJS.parse('foo;') instanceof WrappedUglifyJS.AST_Node); done(); }); }); it("Should be able to filter comments correctly with `--comment all`", function (done) { var command = uglifyjscmd + ' test/input/comments/filter.js --comments all'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "// foo\n/*@preserve*/\n// bar\n\n"); done(); }); }); it("Should be able to filter comments correctly with `--comment `", function (done) { var command = uglifyjscmd + ' test/input/comments/filter.js --comments /r/'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "/*@preserve*/\n// bar\n\n"); done(); }); }); it("Should be able to filter comments correctly with just `--comment`", function (done) { var command = uglifyjscmd + ' test/input/comments/filter.js --comments'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "/*@preserve*/\n\n"); done(); }); }); it("Should append source map to output when using --source-map-inline", function (done) { var command = uglifyjscmd + ' test/input/issue-1323/sample.js --source-map-inline'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" + "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n"); done(); }); }); it("should not append source map to output when not using --source-map-inline", function (done) { var command = uglifyjscmd + ' test/input/issue-1323/sample.js'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n"); done(); }); }); it("Should work with --keep-fnames (mangle only)", function (done) { var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n"); done(); }); }); it("Should work with --keep-fnames (mangle & compress)", function (done) { var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n"); done(); }); }); it("Should work with keep_fnames under mangler options", function (done) { var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n"); done(); }); }); it("Should work with --define (simple)", function (done) { var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "console.log(5);\n"); done(); }); }); it("Should work with --define (nested)", function (done) { var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "console.log(3,5);\n"); done(); }); }); it("Should work with --define (AST_Node)", function (done) { var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "stdout.println(D);\n"); done(); }); }); it("Should work with `--beautify`", function (done) { var command = uglifyjscmd + ' test/input/issue-1482/input.js -b'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, readFileSync("test/input/issue-1482/default.js", "utf8")); done(); }); }); it("Should work with `--beautify bracketize`", function (done) { var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, readFileSync("test/input/issue-1482/bracketize.js", "utf8")); done(); }); }); it("Should process inline source map", function(done) { var command = uglifyjscmd + ' test/input/issue-520/input.js -mc toplevel --in-source-map inline --source-map-inline'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, readFileSync("test/input/issue-520/output.js", "utf8")); done(); }); }); it("Should warn for missing inline source map", function(done) { var command = uglifyjscmd + ' test/input/issue-1323/sample.js --in-source-map inline'; exec(command, function (err, stdout, stderr) { if (err) throw err; assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n"); assert.strictEqual(stderr, "WARN: inline source map not found\n"); done(); }); }); it("Should fail with multiple input and inline source map", function(done) { var command = uglifyjscmd + ' test/input/issue-520/input.js test/input/issue-520/output.js --in-source-map inline --source-map-inline'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stderr, "ERROR: Inline source map only works with singular input\n"); done(); }); }); it("Should fail with acorn and inline source map", function(done) { var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --acorn'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n"); done(); }); }); it("Should fail with SpiderMonkey and inline source map", function(done) { var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --spidermonkey'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n"); done(); }); }); it("Should fail with invalid syntax", function(done) { var command = uglifyjscmd + ' test/input/invalid/simple.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); var lines = stderr.split(/\n/); assert.strictEqual(lines[0], "Parse error at test/input/invalid/simple.js:1,12"); assert.strictEqual(lines[1], "function f(a{}"); assert.strictEqual(lines[2], " ^"); assert.strictEqual(lines[3], "SyntaxError: Unexpected token punc «{», expected punc «,»"); done(); }); }); it("Should fail with correct marking of tabs", function(done) { var command = uglifyjscmd + ' test/input/invalid/tab.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); var lines = stderr.split(/\n/); assert.strictEqual(lines[0], "Parse error at test/input/invalid/tab.js:1,12"); assert.strictEqual(lines[1], "\t\tfoo(\txyz, 0abc);"); assert.strictEqual(lines[2], "\t\t \t ^"); assert.strictEqual(lines[3], "SyntaxError: Invalid syntax: 0abc"); done(); }); }); it("Should fail with correct marking at start of line", function(done) { var command = uglifyjscmd + ' test/input/invalid/eof.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); var lines = stderr.split(/\n/); assert.strictEqual(lines[0], "Parse error at test/input/invalid/eof.js:2,0"); assert.strictEqual(lines[1], "foo, bar("); assert.strictEqual(lines[2], " ^"); assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)"); done(); }); }); it("Should fail with a missing loop body", function(done) { var command = uglifyjscmd + ' test/input/invalid/loop-no-body.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); var lines = stderr.split(/\n/); assert.strictEqual(lines[0], "Parse error at test/input/invalid/loop-no-body.js:2,0"); assert.strictEqual(lines[1], "for (var i = 0; i < 1; i++) "); assert.strictEqual(lines[2], " ^"); assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)"); done(); }); }); it("Should support hyphen as shorthand", function(done) { var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep-fnames=true'; exec(command, function (err, stdout) { if (err) throw err; assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n"); done(); }); }); it("Should throw syntax error (5--)", function(done) { var command = uglifyjscmd + ' test/input/invalid/assign_1.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/assign_1.js:1,18", "console.log(1 || 5--);", " ^", "SyntaxError: Invalid use of -- operator" ].join("\n")); done(); }); }); it("Should throw syntax error (Math.random() /= 2)", function(done) { var command = uglifyjscmd + ' test/input/invalid/assign_2.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/assign_2.js:1,32", "console.log(2 || (Math.random() /= 2));", " ^", "SyntaxError: Invalid assignment" ].join("\n")); done(); }); }); it("Should throw syntax error (++this)", function(done) { var command = uglifyjscmd + ' test/input/invalid/assign_3.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/assign_3.js:1,17", "console.log(3 || ++this);", " ^", "SyntaxError: Invalid use of ++ operator" ].join("\n")); done(); }); }); it("Should throw syntax error (++null)", function(done) { var command = uglifyjscmd + ' test/input/invalid/assign_4.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/assign_4.js:1,0", "++null", "^", "SyntaxError: Invalid use of ++ operator" ].join("\n")); done(); }); }); it("Should throw syntax error (a.=)", function(done) { var command = uglifyjscmd + ' test/input/invalid/dot_1.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/dot_1.js:1,2", "a.=", " ^", "SyntaxError: Unexpected token: operator (=)" ].join("\n")); done(); }); }); it("Should throw syntax error (%.a)", function(done) { var command = uglifyjscmd + ' test/input/invalid/dot_2.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/dot_2.js:1,0", "%.a;", "^", "SyntaxError: Unexpected token: operator (%)" ].join("\n")); done(); }); }); it("Should throw syntax error (a./();)", function(done) { var command = uglifyjscmd + ' test/input/invalid/dot_3.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/dot_3.js:1,2", "a./();", " ^", "SyntaxError: Unexpected token: operator (/)" ].join("\n")); done(); }); }); it("Should throw syntax error ({%: 1})", function(done) { var command = uglifyjscmd + ' test/input/invalid/object.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/object.js:1,13", "console.log({%: 1});", " ^", "SyntaxError: Unexpected token: operator (%)" ].join("\n")); done(); }); }); it("Should throw syntax error (else)", function(done) { var command = uglifyjscmd + ' test/input/invalid/else.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/else.js:1,7", "if (0) else 1;", " ^", "SyntaxError: Unexpected token: keyword (else)" ].join("\n")); done(); }); }); it("Should throw syntax error (return)", function(done) { var command = uglifyjscmd + ' test/input/invalid/return.js'; exec(command, function (err, stdout, stderr) { assert.ok(err); assert.strictEqual(stdout, ""); assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [ "Parse error at test/input/invalid/return.js:1,0", "return 42;", "^", "SyntaxError: 'return' outside of function" ].join("\n")); done(); }); }); }); UglifyJS2-2.8.29/test/mocha/comment-filter.js000066400000000000000000000107071312030606600207250ustar00rootroot00000000000000var UglifyJS = require('../../'); var assert = require("assert"); describe("comment filters", function() { it("Should be able to filter comments by passing regexp", function() { var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\ntest7\n-->!test8"); assert.strictEqual(ast.print_to_string({comments: /^!/}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n"); }); it("Should be able to filter comments with the 'all' option", function() { var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\ntest7\n-->!test8"); assert.strictEqual(ast.print_to_string({comments: "all"}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8\n"); }); it("Should be able to filter commments with the 'some' option", function() { var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/"); assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/\n"); }); it("Should be able to filter comments by passing a function", function() { var ast = UglifyJS.parse("/*TEST 123*/\n//An other comment\n//8 chars."); var f = function(node, comment) { return comment.value.length === 8; }; assert.strictEqual(ast.print_to_string({comments: f}), "/*TEST 123*/\n//8 chars.\n"); }); it("Should be able to filter comments by passing regex in string format", function() { var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\ntest7\n-->!test8"); assert.strictEqual(ast.print_to_string({comments: "/^!/"}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n"); }); it("Should be able to get the comment and comment type when using a function", function() { var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\ntest7\n-->!test8"); var f = function(node, comment) { return comment.type == "comment1" || comment.type == "comment3"; }; assert.strictEqual(ast.print_to_string({comments: f}), "//!test3\n//test4\n//test5\n//!test6\n"); }); it("Should be able to filter comments by passing a boolean", function() { var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\ntest7\n-->!test8"); assert.strictEqual(ast.print_to_string({comments: true}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8\n"); assert.strictEqual(ast.print_to_string({comments: false}), ""); }); it("Should never be able to filter comment5 (shebangs)", function() { var ast = UglifyJS.parse("#!Random comment\n//test1\n/*test2*/"); var f = function(node, comment) { assert.strictEqual(comment.type === "comment5", false); return true; }; assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/\n"); }); it("Should never be able to filter comment5 when using 'some' as filter", function() { var ast = UglifyJS.parse("#!foo\n//foo\n/*@preserve*/\n/* please hide me */"); assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/\n"); }); it("Should have no problem on multiple calls", function() { const options = { comments: /ok/ }; assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}"); assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}"); assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}"); }); it("Should handle shebang and preamble correctly", function() { var code = UglifyJS.minify("#!/usr/bin/node\nvar x = 10;", { fromString: true, output: { preamble: "/* Build */" } }).code; assert.strictEqual(code, "#!/usr/bin/node\n/* Build */\nvar x=10;"); }); it("Should handle preamble without shebang correctly", function() { var code = UglifyJS.minify("var x = 10;", { fromString: true, output: { preamble: "/* Build */" } }).code; assert.strictEqual(code, "/* Build */\nvar x=10;"); }); }); UglifyJS2-2.8.29/test/mocha/comment.js000066400000000000000000000032061312030606600174360ustar00rootroot00000000000000var assert = require("assert"); var uglify = require("../../"); describe("Comment", function() { it("Should recognize eol of single line comments", function() { var tests = [ "//Some comment 1\n>", "//Some comment 2\r>", "//Some comment 3\r\n>", "//Some comment 4\u2028>", "//Some comment 5\u2029>" ]; var fail = function(e) { return e instanceof uglify.JS_Parse_Error && e.message === "Unexpected token: operator (>)" && e.line === 2 && e.col === 0; } for (var i = 0; i < tests.length; i++) { assert.throws(function() { uglify.parse(tests[i], {fromString: true}) }, fail, tests[i]); } }); it("Should update the position of a multiline comment correctly", function() { var tests = [ "/*Some comment 1\n\n\n*/\n>\n\n\n\n\n\n", "/*Some comment 2\r\n\r\n\r\n*/\r\n>\n\n\n\n\n\n", "/*Some comment 3\r\r\r*/\r>\n\n\n\n\n\n", "/*Some comment 4\u2028\u2028\u2028*/\u2028>\n\n\n\n\n\n", "/*Some comment 5\u2029\u2029\u2029*/\u2029>\n\n\n\n\n\n" ]; var fail = function(e) { return e instanceof uglify.JS_Parse_Error && e.message === "Unexpected token: operator (>)" && e.line === 5 && e.col === 0; } for (var i = 0; i < tests.length; i++) { assert.throws(function() { uglify.parse(tests[i], {fromString: true}) }, fail, tests[i]); } }); }); UglifyJS2-2.8.29/test/mocha/comment_before_constant.js000066400000000000000000000017321312030606600226730ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); describe("comment before constant", function() { var js = 'function f() { /*c1*/ var /*c2*/ foo = /*c3*/ false; return foo; }'; it("Should test comment before constant is retained and output after mangle.", function() { var result = Uglify.minify(js, { fromString: true, compress: { collapse_vars: false, reduce_vars: false }, mangle: {}, output: { comments: true }, }); assert.strictEqual(result.code, 'function f(){/*c1*/var/*c2*/n=/*c3*/!1;return n}'); }); it("Should test code works when comments disabled.", function() { var result = Uglify.minify(js, { fromString: true, compress: { collapse_vars: false, reduce_vars: false }, mangle: {}, output: { comments: false }, }); assert.strictEqual(result.code, 'function f(){var n=!1;return n}'); }); }); UglifyJS2-2.8.29/test/mocha/directives.js000066400000000000000000000342471312030606600201460ustar00rootroot00000000000000var assert = require("assert"); var uglify = require("../../"); describe("Directives", function() { it ("Should allow tokenizer to store directives state", function() { var tokenizer = uglify.tokenizer("", "foo.js"); // Stack level 0 assert.strictEqual(tokenizer.has_directive("use strict"), false); assert.strictEqual(tokenizer.has_directive("use asm"), false); assert.strictEqual(tokenizer.has_directive("use thing"), false); // Stack level 2 tokenizer.push_directives_stack(); tokenizer.push_directives_stack(); tokenizer.add_directive("use strict"); assert.strictEqual(tokenizer.has_directive("use strict"), true); assert.strictEqual(tokenizer.has_directive("use asm"), false); assert.strictEqual(tokenizer.has_directive("use thing"), false); // Stack level 3 tokenizer.push_directives_stack(); tokenizer.add_directive("use strict"); tokenizer.add_directive("use asm"); assert.strictEqual(tokenizer.has_directive("use strict"), true); assert.strictEqual(tokenizer.has_directive("use asm"), true); assert.strictEqual(tokenizer.has_directive("use thing"), false); // Stack level 2 tokenizer.pop_directives_stack(); assert.strictEqual(tokenizer.has_directive("use strict"), true); assert.strictEqual(tokenizer.has_directive("use asm"), false); assert.strictEqual(tokenizer.has_directive("use thing"), false); // Stack level 3 tokenizer.push_directives_stack(); tokenizer.add_directive("use thing"); tokenizer.add_directive("use\\\nasm"); assert.strictEqual(tokenizer.has_directive("use strict"), true); assert.strictEqual(tokenizer.has_directive("use asm"), false); // Directives are strict! assert.strictEqual(tokenizer.has_directive("use thing"), true); // Stack level 2 tokenizer.pop_directives_stack(); assert.strictEqual(tokenizer.has_directive("use strict"), true); assert.strictEqual(tokenizer.has_directive("use asm"), false); assert.strictEqual(tokenizer.has_directive("use thing"), false); // Stack level 1 tokenizer.pop_directives_stack(); assert.strictEqual(tokenizer.has_directive("use strict"), false); assert.strictEqual(tokenizer.has_directive("use asm"), false); assert.strictEqual(tokenizer.has_directive("use thing"), false); // Stack level 0 tokenizer.pop_directives_stack(); assert.strictEqual(tokenizer.has_directive("use strict"), false); assert.strictEqual(tokenizer.has_directive("use asm"), false); assert.strictEqual(tokenizer.has_directive("use thing"), false); }); it("Should know which strings are directive and which ones are not", function() { var test_directive = function(tokenizer, test) { test.directives.map(function(directive) { assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test.input); }); test.non_directives.map(function(fake_directive) { assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test.input); }); } var tests = [ { input: '"use strict"\n', directives: ["use strict"], non_directives: ["use asm"] }, { input: '"use\\\nstrict";', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: '"use strict"\n"use asm"\n"use bar"\n', directives: ["use strict", "use asm", "use bar"], non_directives: ["use foo", "use\\x20strict"] }, { input: '"use \\\nstrict";"use strict";', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: '"\\76";', directives: [], non_directives: [">", "\\76"] }, { input: '"use strict"', // no ; or newline directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: ';"use strict"', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, // Duplicate above code but put it in a function { input: 'function foo() {"use strict"\n', directives: ["use strict"], non_directives: ["use asm"] }, { input: 'function foo() {"use\\\nstrict";', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: 'function foo() {"use strict"\n"use asm"\n"use bar"\n', directives: ["use strict", "use asm", "use bar"], non_directives: ["use foo", "use\\x20strict"] }, { input: 'function foo() {"use \\\nstrict";"use strict";', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: 'var foo = function() {"\\76";', directives: [], non_directives: [">", "\\76"] }, { input: 'var foo = function() {"use strict"', // no ; or newline directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: 'var foo = function() {;"use strict"', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, // Special cases { input: '"1";"2";"3";"4";;"5"', directives: ["1", "2", "3", "4"], non_directives: ["5", "6", "use strict", "use asm"] }, { input: 'if(1){"use strict";', directives: [], non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"] }, { input: '"use strict";try{"use asm";', directives: ["use strict"], non_directives: ["use\nstrict", "use \nstrict", "use asm"] } ]; for (var i = 0; i < tests.length; i++) { // Fail parser deliberately to get state at failure var tokenizer = uglify.tokenizer(tests[i].input + "]", "foo.js"); try { var parser = uglify.parse(tokenizer); throw new Error("Expected parser to fail"); } catch (e) { assert.strictEqual(e instanceof uglify.JS_Parse_Error, true); assert.strictEqual(e.message, "Unexpected token: punc (])"); } test_directive(tokenizer, tests[i]); } }); it("Should test EXPECT_DIRECTIVE RegExp", function() { [ ["", true], ["'test';", true], ["'test';;", true], ["'tests';\n", true], ["'tests'", false], ["'tests'; \n\t", true], ["'tests';\n\n", true], ["\n\n\"use strict\";\n\n", true] ].forEach(function(test) { var out = uglify.OutputStream(); out.print(test[0]); out.print_string("", null, true); assert.strictEqual(out.get() === test[0] + ';""', test[1], test[0]); }); }); it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() { assert.strictEqual( uglify.minify( '"use strict";\'use strict\';"use strict";"use strict";;\'use strict\';console.log(\'use strict\');', {fromString: true, output: {beautify: true, quote_style: 3}, compress: false} ).code, '"use strict";\n\n\'use strict\';\n\n"use strict";\n\n"use strict";\n\n;\'use strict\';\n\nconsole.log(\'use strict\');' ); }); it("Should not add double semicolons in non-scoped block statements to avoid strings becoming directives", function() { var tests = [ [ '{"use\x20strict"}', '{"use strict"}' ], [ 'function foo(){"use\x20strict";}', // Valid place for directives 'function foo(){"use strict"}' ], [ 'try{"use\x20strict"}catch(e){}finally{"use\x20strict"}', 'try{"use strict"}catch(e){}finally{"use strict"}' ], [ 'if(1){"use\x20strict"} else {"use strict"}', 'if(1){"use strict"}else{"use strict"}' ] ]; for (var i = 0; i < tests.length; i++) { assert.strictEqual( uglify.minify(tests[i][0], {fromString: true, quote_style: 3, compress: false, mangle: false}).code, tests[i][1], tests[i][0] ); } }); it("Should add double semicolon when relying on automatic semicolon insertion", function() { var code = uglify.minify('"use strict";"use\\x20strict";', {fromString: true, output: {semicolons: false}, compress: false} ).code; assert.strictEqual(code, '"use strict";;"use strict"\n'); }); it("Should check quote style of directives", function() { var tests = [ // 0. Prefer double quotes, unless string contains more double quotes than single quotes [ '"testing something";', 0, '"testing something";' ], [ "'use strict';", 0, '"use strict";' ], [ '"\\\'use strict\\\'";', // Not a directive as it contains quotes 0, ';"\'use strict\'";', ], [ "'\"use strict\"';", 0, "'\"use strict\"';", ], // 1. Always use single quote [ '"testing something";', 1, "'testing something';" ], [ "'use strict';", 1, "'use strict';" ], [ '"\'use strict\'";', 1, // Intentionally causes directive breakage at cost of less logic, usage should be rare anyway "'\\'use strict\\'';", ], [ "'\\'use strict\\'';", // Not a valid directive 1, "'\\'use strict\\'';" // But no ; necessary as directive stays invalid ], [ "'\"use strict\"';", 1, "'\"use strict\"';", ], // 2. Always use double quote [ '"testing something";', 2, '"testing something";' ], [ "'use strict';", 2, '"use strict";' ], [ '"\'use strict\'";', 2, "\"'use strict'\";", ], [ "'\"use strict\"';", 2, // Intentionally causes directive breakage at cost of less logic, usage should be rare anyway '"\\\"use strict\\\"";', ], [ '"\\"use strict\\"";', // Not a valid directive 2, '"\\"use strict\\"";' // But no ; necessary as directive stays invalid ], // 3. Always use original [ '"testing something";', 3, '"testing something";' ], [ "'use strict';", 3, "'use strict';", ], [ '"\'use strict\'";', 3, '"\'use strict\'";', ], [ "'\"use strict\"';", 3, "'\"use strict\"';", ], ]; for (var i = 0; i < tests.length; i++) { assert.strictEqual( uglify.minify(tests[i][0], {fromString: true, output:{quote_style: tests[i][1]}, compress: false}).code, tests[i][2], tests[i][0] + " using mode " + tests[i][1] ); } }); it("Should be able to compress without side effects", function() { // NOTE: the "use asm" directive disables any optimisation after being defined var tests = [ [ '"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");', '"use strict";"use foo";doSomething("foo");', 'function f(){ "use strict" }', 'function f(){ "use asm" }', 'function f(){ "use nondirective" }', 'function f(){ ;"use strict" }', 'function f(){ "use \n"; }', ], [ // Nothing gets optimised in the compressor because "use asm" is the first statement '"use asm";"use\\x20strict";1+1;', '"use asm";;"use strict";1+1;', // Yet, the parser noticed that "use strict" wasn't a directive 'function f(){"use strict"}', 'function f(){"use asm"}', 'function f(){"use nondirective"}', 'function f(){}', 'function f(){}', ] ]; for (var i = 0; i < tests.length; i++) { assert.strictEqual( uglify.minify(tests[i][0], {fromString: true}).code, tests[i][1], tests[i][0] ); } }); }); UglifyJS2-2.8.29/test/mocha/getter-setter.js000066400000000000000000000044051312030606600205740ustar00rootroot00000000000000var UglifyJS = require('../../'); var assert = require("assert"); describe("Getters and setters", function() { it("Should not accept operator symbols as getter/setter name", function() { var illegalOperators = [ "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]; var generator = function() { var results = []; for (var i in illegalOperators) { results.push({ code: "var obj = { get " + illegalOperators[i] + "() { return test; }};", operator: illegalOperators[i], method: "get" }); results.push({ code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};", operator: illegalOperators[i], method: "set" }); } return results; }; var testCase = function(data) { return function() { UglifyJS.parse(data.code); }; }; var fail = function(data) { return function (e) { return e instanceof UglifyJS.JS_Parse_Error && e.message === "Unexpected token: operator (" + data.operator + ")"; }; }; var errorMessage = function(data) { return "Expected but didn't get a syntax error while parsing following line:\n" + data.code; }; var tests = generator(); for (var i = 0; i < tests.length; i++) { var test = tests[i]; assert.throws(testCase(test), fail(test), errorMessage(test)); } }); }); UglifyJS2-2.8.29/test/mocha/glob.js000066400000000000000000000052131312030606600167170ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); var path = require("path"); describe("minify() with input file globs", function() { it("minify() with one input file glob string.", function() { var result = Uglify.minify("test/input/issue-1242/foo.*"); assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);'); }); it("minify() with an array of one input file glob.", function() { var result = Uglify.minify([ "test/input/issue-1242/b*.es5", ]); assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}'); }); it("minify() with an array of multiple input file globs.", function() { var result = Uglify.minify([ "test/input/issue-1242/???.es5", "test/input/issue-1242/*.js", ], { compress: { toplevel: true } }); assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);'); }); it("should throw with non-matching glob string", function() { var glob = "test/input/issue-1242/blah.*"; assert.strictEqual(Uglify.simple_glob(glob).length, 1); assert.strictEqual(Uglify.simple_glob(glob)[0], glob); assert.throws(function() { Uglify.minify(glob); }, "should throw file not found"); }); it('"?" in glob string should not match "/"', function() { var glob = "test/input?issue-1242/foo.*"; assert.strictEqual(Uglify.simple_glob(glob).length, 1); assert.strictEqual(Uglify.simple_glob(glob)[0], glob); assert.throws(function() { Uglify.minify(glob); }, "should throw file not found"); }); it("should handle special characters in glob string", function() { var result = Uglify.minify("test/input/issue-1632/^{*}[???](*)+$.??"); assert.strictEqual(result.code, "console.log(x);"); }); it("should handle array of glob strings - matching and otherwise", function() { var dir = "test/input/issue-1242"; var matches = Uglify.simple_glob([ path.join(dir, "b*.es5"), path.join(dir, "z*.es5"), path.join(dir, "*.js"), ]); assert.strictEqual(matches.length, 4); assert.strictEqual(matches[0], path.join(dir, "bar.es5")); assert.strictEqual(matches[1], path.join(dir, "baz.es5")); assert.strictEqual(matches[2], path.join(dir, "z*.es5")); assert.strictEqual(matches[3], path.join(dir, "qux.js")); }); }); UglifyJS2-2.8.29/test/mocha/huge-number-of-comments.js000066400000000000000000000012361312030606600224400ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); describe("Huge number of comments.", function() { it("Should parse and compress code with thousands of consecutive comments", function() { var js = 'function lots_of_comments(x) { return 7 -'; var i; for (i = 1; i <= 5000; ++i) { js += "// " + i + "\n"; } for (; i <= 10000; ++i) { js += "/* " + i + " */ /**/"; } js += "x; }"; var result = Uglify.minify(js, { fromString: true, mangle: false, compress: {} }); assert.strictEqual(result.code, "function lots_of_comments(x){return 7-x}"); }); }); UglifyJS2-2.8.29/test/mocha/input-sourcemaps.js000066400000000000000000000043351312030606600213160ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); var SourceMapConsumer = require("source-map").SourceMapConsumer; describe("input sourcemaps", function() { var transpilemap, map; function getMap() { return { "version": 3, "sources": ["index.js"], "names": [], "mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ", "file": "bundle.js", "sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"] }; } function prepareMap(sourceMap) { var transpiled = '"use strict";\n\n' + 'var foo = function foo(x) {\n return "foo " + x;\n};\n' + 'console.log(foo("bar"));\n\n' + '//# sourceMappingURL=bundle.js.map'; transpilemap = sourceMap || getMap(); var result = Uglify.minify(transpiled, { fromString: true, inSourceMap: transpilemap, outSourceMap: true }); map = new SourceMapConsumer(result.map); } beforeEach(function () { prepareMap(); }); it("Should copy over original sourcesContent", function() { assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]); }); it("Should copy sourcesContent if sources are relative", function () { var relativeMap = getMap(); relativeMap.sources = ['./index.js']; prepareMap(relativeMap); assert.notEqual(map.sourcesContent, null); assert.equal(map.sourcesContent.length, 1); assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]); }); it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882)", function() { // The original source has only 2 lines, check that mappings don't have more lines var msg = "Mapping should not have higher line number than the original file had"; map.eachMapping(function(mapping) { assert.ok(mapping.originalLine <= 2, msg) }); map.allGeneratedPositionsFor({source: "index.js", line: 1, column: 1}).forEach(function(pos) { assert.ok(pos.line <= 2, msg); }) }); }); UglifyJS2-2.8.29/test/mocha/let.js000066400000000000000000000021561312030606600165630ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); describe("let", function() { it("Should not produce `let` as a variable name in mangle", function(done) { this.timeout(10000); // Produce a lot of variables in a function and run it through mangle. var s = '"use strict"; function foo() {'; for (var i = 0; i < 21000; ++i) { s += "var v" + i + "=0;"; } s += '}'; var result = Uglify.minify(s, {fromString: true, compress: false}); // Verify that select keywords and reserved keywords not produced assert.strictEqual(result.code.indexOf("var let="), -1); assert.strictEqual(result.code.indexOf("var do="), -1); assert.strictEqual(result.code.indexOf("var var="), -1); // Verify that the variable names that appeared immediately before // and after the erroneously generated `let` variable name still exist // to show the test generated enough symbols. assert(result.code.indexOf("var ket=") >= 0); assert(result.code.indexOf("var met=") >= 0); done(); }); }); UglifyJS2-2.8.29/test/mocha/line-endings.js000066400000000000000000000036021312030606600203500ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); describe("line-endings", function() { var options = { fromString: true, mangle: false, compress: false, output: { beautify: false, comments: /^!/, } }; var expected_code = '/*!one\n2\n3*/\nfunction f(x){if(x)return 3}'; it("Should parse LF line endings", function() { var js = '/*!one\n2\n3*///comment\nfunction f(x) {\n if (x)\n//comment\n return 3;\n}\n'; var result = Uglify.minify(js, options); assert.strictEqual(result.code, expected_code); }); it("Should parse CR/LF line endings", function() { var js = '/*!one\r\n2\r\n3*///comment\r\nfunction f(x) {\r\n if (x)\r\n//comment\r\n return 3;\r\n}\r\n'; var result = Uglify.minify(js, options); assert.strictEqual(result.code, expected_code); }); it("Should parse CR line endings", function() { var js = '/*!one\r2\r3*///comment\rfunction f(x) {\r if (x)\r//comment\r return 3;\r}\r'; var result = Uglify.minify(js, options); assert.strictEqual(result.code, expected_code); }); it("Should not allow line terminators in regexp", function() { var inputs = [ "/\n/", "/\r/", "/\u2028/", "/\u2029/", "/\\\n/", "/\\\r/", "/\\\u2028/", "/\\\u2029/", "/someRandomTextLike[]()*AndThen\n/" ] var test = function(input) { return function() { Uglify.parse(input); } } var fail = function(e) { return e instanceof Uglify.JS_Parse_Error && e.message === "Unexpected line terminator"; } for (var i = 0; i < inputs.length; i++) { assert.throws(test(inputs[i]), fail); } }); }); UglifyJS2-2.8.29/test/mocha/minify-file-map.js000066400000000000000000000035421312030606600207620ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); describe("Input file as map", function() { it("Should accept object", function() { var jsMap = { '/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};' }; var result = Uglify.minify(jsMap, {fromString: true, outSourceMap: true}); var map = JSON.parse(result.map); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); assert.deepEqual(map.sources, ['/scripts/foo.js']); assert.strictEqual(map.file, undefined); result = Uglify.minify(jsMap, {fromString: true, outFileName: 'out.js'}); assert.strictEqual(result.map, null); result = Uglify.minify(jsMap, {fromString: true, outFileName: 'out.js', outSourceMap: true}); map = JSON.parse(result.map); assert.strictEqual(map.file, 'out.js'); }); it("Should accept array of objects and strings", function() { var jsSeq = [ {'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'}, 'var bar = 15;' ]; var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true}); var map = JSON.parse(result.map); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;'); assert.strictEqual(map.sources[0], '/scripts/foo.js'); }); it("Should correctly include source", function() { var jsSeq = [ {'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'}, 'var bar = 15;' ]; var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true, sourceMapIncludeSources: true}); var map = JSON.parse(result.map); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;'); assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};', 'var bar = 15;']); }); }); UglifyJS2-2.8.29/test/mocha/minify.js000066400000000000000000000200301312030606600172610ustar00rootroot00000000000000var Uglify = require('../../'); var assert = require("assert"); var readFileSync = require("fs").readFileSync; describe("minify", function() { it("Should test basic sanity of minify with default options", function() { var js = 'function foo(bar) { if (bar) return 3; else return 7; var u = not_called(); }'; var result = Uglify.minify(js, {fromString: true}); assert.strictEqual(result.code, 'function foo(n){return n?3:7}'); }); describe("keep_quoted_props", function() { it("Should preserve quotes in object literals", function() { var js = 'var foo = {"x": 1, y: 2, \'z\': 3};'; var result = Uglify.minify(js, { fromString: true, output: { keep_quoted_props: true }}); assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};'); }); it("Should preserve quote styles when quote_style is 3", function() { var js = 'var foo = {"x": 1, y: 2, \'z\': 3};'; var result = Uglify.minify(js, { fromString: true, output: { keep_quoted_props: true, quote_style: 3 }}); assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};'); }); it("Should not preserve quotes in object literals when disabled", function() { var js = 'var foo = {"x": 1, y: 2, \'z\': 3};'; var result = Uglify.minify(js, { fromString: true, output: { keep_quoted_props: false, quote_style: 3 }}); assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); }); }); describe("mangleProperties", function() { it("Shouldn't mangle quoted properties", function() { var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};'; var result = Uglify.minify(js, { fromString: true, compress: { properties: false }, mangleProperties: { ignore_quoted: true }, output: { keep_quoted_props: true, quote_style: 3 } }); assert.strictEqual(result.code, 'a["foo"]="bar",a.a="red",x={"bar":10};'); }); }); describe("inSourceMap", function() { it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() { var result = Uglify.minify('./test/input/issue-1236/simple.js', { outSourceMap: "simple.min.js.map", inSourceMap: "./test/input/issue-1236/simple.js.map", sourceMapIncludeSources: true }); var map = JSON.parse(result.map); assert.equal(map.file, 'simple.min.js'); assert.equal(map.sourcesContent.length, 1); assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));'); }); it("Should process inline source map", function() { var code = Uglify.minify("./test/input/issue-520/input.js", { compress: { toplevel: true }, inSourceMap: "inline", sourceMapInline: true }).code + "\n"; assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8")); }); it("Should warn for missing inline source map", function() { var warn_function = Uglify.AST_Node.warn_function; var warnings = []; Uglify.AST_Node.warn_function = function(txt) { warnings.push(txt); }; try { var result = Uglify.minify("./test/input/issue-1323/sample.js", { inSourceMap: "inline", mangle: false, }); assert.strictEqual(result.code, "var bar=function(){function foo(bar){return bar}return foo}();"); assert.strictEqual(warnings.length, 1); assert.strictEqual(warnings[0], "inline source map not found"); } finally { Uglify.AST_Node.warn_function = warn_function; } }); it("Should fail with multiple input and inline source map", function() { assert.throws(function() { Uglify.minify([ "./test/input/issue-520/input.js", "./test/input/issue-520/output.js" ], { inSourceMap: "inline", sourceMapInline: true }); }); }); it("Should fail with SpiderMonkey and inline source map", function() { assert.throws(function() { Uglify.minify("./test/input/issue-520/input.js", { inSourceMap: "inline", sourceMapInline: true, spidermonkey: true }); }); }); }); describe("sourceMapInline", function() { it("should append source map to output js when sourceMapInline is enabled", function() { var result = Uglify.minify('var a = function(foo) { return foo; };', { fromString: true, sourceMapInline: true }); var code = result.code; assert.strictEqual(code, "var a=function(n){return n};\n" + "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIj8iXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsR0FBSUEsR0FBSSxTQUFTQyxHQUFPLE1BQU9BIn0="); }); it("should not append source map to output js when sourceMapInline is not enabled", function() { var result = Uglify.minify('var a = function(foo) { return foo; };', { fromString: true }); var code = result.code; assert.strictEqual(code, "var a=function(n){return n};"); }); }); describe("#__PURE__", function() { it("should drop #__PURE__ hint after use", function() { var result = Uglify.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', { fromString: true, output: { comments: "all", beautify: false, } }); var code = result.code; assert.strictEqual(code, "// comment1 comment2\nbar();"); }); it("should not drop #__PURE__ hint if function is retained", function() { var result = Uglify.minify("var a = /*#__PURE__*/(function(){ foo(); })();", { fromString: true, output: { comments: "all", beautify: false, } }); var code = result.code; assert.strictEqual(code, "var a=/*#__PURE__*/function(){foo()}();"); }) }); describe("JS_Parse_Error", function() { it("should throw syntax error", function() { assert.throws(function() { Uglify.minify("function f(a{}", { fromString: true }); }, function(err) { assert.ok(err instanceof Error); assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token punc «{», expected punc «,»"); assert.strictEqual(err.filename, 0); assert.strictEqual(err.line, 1); assert.strictEqual(err.col, 12); return true; }); }); }); describe("Compressor", function() { it("should be backward compatible with ast.transform(compressor)", function() { var ast = Uglify.parse("function f(a){for(var i=0;i";'], ['"\\0"', '"\\0";'], ['"\\08"', '"\\08";'], ['"\\008"', '"\\08";'], ['"\\0008"', '"\\08";'], ['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'], ['"use\\\n strict";\n"\\07";', ';"use strict";"\07";'] ]; for (var test in tests) { var output = UglifyJS.parse(tests[test][0]).print_to_string(); assert.equal(output, tests[test][1]); } }); it("Should not throw error when digit is 8 or 9", function() { assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";'); assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";'); }); }); UglifyJS2-2.8.29/test/mocha/with.js000066400000000000000000000016411312030606600167500ustar00rootroot00000000000000var assert = require("assert"); var uglify = require("../../"); describe("With", function() { it("Should throw syntaxError when using with statement in strict mode", function() { var code = '"use strict";\nthrow NotEarlyError;\nwith ({}) { }'; var test = function() { uglify.parse(code); } var error = function(e) { return e instanceof uglify.JS_Parse_Error && e.message === "Strict mode may not include a with statement"; } assert.throws(test, error); }); it("Should set uses_with for scopes involving With statements", function() { var ast = uglify.parse("with(e) {f(1, 2)}"); ast.figure_out_scope(); assert.equal(ast.uses_with, true); assert.equal(ast.body[0].expression.scope.uses_with, true); assert.equal(ast.body[0].body.body[0].body.expression.scope.uses_with, true); }); }); UglifyJS2-2.8.29/test/mozilla-ast.js000066400000000000000000000051231312030606600171410ustar00rootroot00000000000000// Testing UglifyJS <-> SpiderMonkey AST conversion "use strict"; var acorn = require("acorn"); var ufuzz = require("./ufuzz"); var UglifyJS = require(".."); function try_beautify(code) { var beautified; try { beautified = UglifyJS.minify(code, { fromString: true, compress: false, mangle: false, output: { beautify: true, bracketize: true } }); } catch (ex) { beautified = { error: ex }; } if (beautified.error) { console.log("// !!! beautify failed !!!"); console.log(beautified.error.stack); console.log(code); } else { console.log("// (beautified)"); console.log(beautified.code); } } function test(original, estree, description) { var transformed; try { transformed = UglifyJS.minify(estree, { fromString: true, compress: false, mangle: false, spidermonkey: true }); } catch (ex) { transformed = { error: ex }; } if (transformed.error || original !== transformed.code) { console.log("//============================================================="); console.log("// !!!!!! Failed... round", round); console.log("// original code"); try_beautify(original); console.log(); console.log(); console.log("//-------------------------------------------------------------"); console.log("//", description); if (transformed.error) { console.log(transformed.error.stack); } else { try_beautify(transformed.code); } console.log("!!!!!! Failed... round", round); process.exit(1); } } var num_iterations = ufuzz.num_iterations; for (var round = 1; round <= num_iterations; round++) { process.stdout.write(round + " of " + num_iterations + "\r"); var code = ufuzz.createTopLevelCode(); var uglified = { ast: UglifyJS.parse(code), code: UglifyJS.minify(code, { fromString: true, compress: false, mangle: false }).code }; test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()"); try { test(uglified.code, acorn.parse(code), "acorn.parse()"); } catch (e) { console.log("//============================================================="); console.log("// acorn parser failed... round", round); console.log(e); console.log("// original code"); console.log(code); } } console.log(); UglifyJS2-2.8.29/test/run-tests.js000077500000000000000000000267521312030606600166670ustar00rootroot00000000000000#! /usr/bin/env node var U = require("../tools/node"); var path = require("path"); var fs = require("fs"); var assert = require("assert"); var sandbox = require("./sandbox"); var tests_dir = path.dirname(module.filename); var failures = 0; var failed_files = {}; run_compress_tests(); if (failures) { console.error("\n!!! Failed " + failures + " test cases."); console.error("!!! " + Object.keys(failed_files).join(", ")); process.exit(1); } var mocha_tests = require("./mocha.js"); mocha_tests(); var run_sourcemaps_tests = require('./sourcemaps'); run_sourcemaps_tests(); /* -----[ utils ]----- */ function tmpl() { return U.string_template.apply(this, arguments); } function log() { var txt = tmpl.apply(this, arguments); console.log("%s", txt); } function log_directory(dir) { log("*** Entering [{dir}]", { dir: dir }); } function log_start_file(file) { log("--- {file}", { file: file }); } function log_test(name) { log(" Running test [{name}]", { name: name }); } function find_test_files(dir) { var files = fs.readdirSync(dir).filter(function(name){ return /\.js$/i.test(name); }); if (process.argv.length > 2) { var x = process.argv.slice(2); files = files.filter(function(f){ return x.indexOf(f) >= 0; }); } return files; } function test_directory(dir) { return path.resolve(tests_dir, dir); } function as_toplevel(input, mangle_options) { if (!(input instanceof U.AST_BlockStatement)) throw new Error("Unsupported input syntax"); for (var i = 0; i < input.body.length; i++) { var stat = input.body[i]; if (stat instanceof U.AST_SimpleStatement && stat.body instanceof U.AST_String) input.body[i] = new U.AST_Directive(stat.body); else break; } var toplevel = new U.AST_Toplevel(input); toplevel.figure_out_scope(mangle_options); return toplevel; } function run_compress_tests() { var dir = test_directory("compress"); log_directory("compress"); var files = find_test_files(dir); function test_file(file) { log_start_file(file); function test_case(test) { log_test(test.name); U.base54.reset(); var output_options = test.beautify || {}; var expect; if (test.expect) { expect = make_code(as_toplevel(test.expect, test.mangle), output_options); } else { expect = test.expect_exact; } var input = as_toplevel(test.input, test.mangle); var input_code = make_code(input, output_options); var input_formatted = make_code(test.input, { beautify: true, quote_style: 3, keep_quoted_props: true }); if (test.mangle_props) { input = U.mangle_properties(input, test.mangle_props); } var options = U.defaults(test.options, { warnings: false }); var warnings_emitted = []; var original_warn_function = U.AST_Node.warn_function; if (test.expect_warnings) { U.AST_Node.warn_function = function(text) { warnings_emitted.push("WARN: " + text); }; if (!options.warnings) options.warnings = true; } var cmp = new U.Compressor(options, true); var output = cmp.compress(input); output.figure_out_scope(test.mangle); if (test.mangle) { output.compute_char_frequency(test.mangle); output.mangle_names(test.mangle); } output = make_code(output, output_options); if (expect != output) { log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", { input: input_formatted, output: output, expected: expect }); failures++; failed_files[file] = 1; } else { // expect == output try { var reparsed_ast = U.parse(output); } catch (ex) { log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", { input: input_formatted, output: output, error: ex.toString(), }); failures++; failed_files[file] = 1; } if (test.expect_warnings) { U.AST_Node.warn_function = original_warn_function; var expected_warnings = make_code(test.expect_warnings, { beautify: false, quote_style: 2, // force double quote to match JSON }); warnings_emitted = warnings_emitted.map(function(input) { return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/"); }); var actual_warnings = JSON.stringify(warnings_emitted); if (expected_warnings != actual_warnings) { log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", { input: input_formatted, expected_warnings: expected_warnings, actual_warnings: actual_warnings, }); failures++; failed_files[file] = 1; } } if (test.expect_stdout) { var stdout = sandbox.run_code(input_code); if (test.expect_stdout === true) { test.expect_stdout = stdout; } if (!sandbox.same_stdout(test.expect_stdout, stdout)) { log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", { input: input_formatted, expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR", expected: test.expect_stdout, actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR", actual: stdout, }); failures++; failed_files[file] = 1; } else { stdout = sandbox.run_code(output); if (!sandbox.same_stdout(test.expect_stdout, stdout)) { log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", { input: input_formatted, expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR", expected: test.expect_stdout, actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR", actual: stdout, }); failures++; failed_files[file] = 1; } } } } } var tests = parse_test(path.resolve(dir, file)); for (var i in tests) if (tests.hasOwnProperty(i)) { test_case(tests[i]); } } files.forEach(function(file){ test_file(file); }); } function parse_test(file) { var script = fs.readFileSync(file, "utf8"); // TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348 try { var ast = U.parse(script, { filename: file }); } catch (e) { console.log("Caught error while parsing tests in " + file + "\n"); console.log(e); throw e; } var tests = {}; var tw = new U.TreeWalker(function(node, descend){ if (node instanceof U.AST_LabeledStatement && tw.parent() instanceof U.AST_Toplevel) { var name = node.label.name; if (name in tests) { throw new Error('Duplicated test name "' + name + '" in ' + file); } tests[name] = get_one_test(name, node.body); return true; } if (!(node instanceof U.AST_Toplevel)) croak(node); }); ast.walk(tw); return tests; function croak(node) { throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", { file: file, line: node.start.line, col: node.start.col, code: make_code(node, { beautify: false }) })); } function read_string(stat) { if (stat.TYPE == "SimpleStatement") { var body = stat.body; switch(body.TYPE) { case "String": return body.value; case "Array": return body.elements.map(function(element) { if (element.TYPE !== "String") throw new Error("Should be array of strings"); return element.value; }).join("\n"); } } throw new Error("Should be string or array of strings"); } function get_one_test(name, block) { var test = { name: name, options: {} }; var tw = new U.TreeWalker(function(node, descend){ if (node instanceof U.AST_Assign) { if (!(node.left instanceof U.AST_SymbolRef)) { croak(node); } var name = node.left.name; test[name] = evaluate(node.right); return true; } if (node instanceof U.AST_LabeledStatement) { var label = node.label; assert.ok( ["input", "expect", "expect_exact", "expect_warnings", "expect_stdout"].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", { name: label.name, line: label.start.line, col: label.start.col }) ); var stat = node.body; if (label.name == "expect_exact") { test[label.name] = read_string(stat); } else if (label.name == "expect_stdout") { if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) { test[label.name] = stat.body.value; } else { test[label.name] = read_string(stat) + "\n"; } } else { test[label.name] = stat; } return true; } }); block.walk(tw); return test; }; } function make_code(ast, options) { options.inline_script = true; var stream = U.OutputStream(options); ast.print(stream); return stream.get(); } function evaluate(code) { if (code instanceof U.AST_Node) code = make_code(code, { beautify: true }); return new Function("return(" + code + ")")(); } UglifyJS2-2.8.29/test/sandbox.js000066400000000000000000000046551312030606600163540ustar00rootroot00000000000000var vm = require("vm"); function safe_log(arg, level) { if (arg) switch (typeof arg) { case "function": return arg.toString(); case "object": if (/Error$/.test(arg.name)) return arg.toString(); arg.constructor.toString(); if (level--) for (var key in arg) { if (!Object.getOwnPropertyDescriptor(arg, key).get) { arg[key] = safe_log(arg[key], level); } } } return arg; } var FUNC_TOSTRING = [ "Function.prototype.toString = Function.prototype.valueOf = function() {", " var id = 0;", " return function() {", ' if (this === Array) return "[Function: Array]";', ' if (this === Object) return "[Function: Object]";', " var i = this.name;", ' if (typeof i != "number") {', " i = ++id;", ' Object.defineProperty(this, "name", {', " get: function() {", " return i;", " }", " });", " }", ' return "[Function: " + i + "]";', " }", "}();", ].join("\n"); exports.run_code = function(code) { var stdout = ""; var original_write = process.stdout.write; process.stdout.write = function(chunk) { stdout += chunk; }; try { vm.runInNewContext([ FUNC_TOSTRING, "!function() {", code, "}();", ].join("\n"), { console: { log: function() { return console.log.apply(console, [].map.call(arguments, function(arg) { return safe_log(arg, 3); })); } } }, { timeout: 5000 }); return stdout; } catch (ex) { return ex; } finally { process.stdout.write = original_write; } }; exports.same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) { if (typeof expected != typeof actual) return false; if (typeof expected != "string") { if (expected.name != actual.name) return false; expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1); actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1); } return expected == actual; } : function(expected, actual) { return typeof expected == typeof actual && expected.toString() == actual.toString(); }; UglifyJS2-2.8.29/test/sourcemaps.js000066400000000000000000000015631312030606600170720ustar00rootroot00000000000000var UglifyJS = require(".."); var ok = require("assert"); module.exports = function () { console.log("--- Sourcemaps tests"); var basic = source_map([ 'var x = 1 + 1;' ].join('\n')); ok.equal(basic.version, 3); ok.deepEqual(basic.names, ['x']); var issue836 = source_map([ "({", " get enabled() {", " return 3;", " },", " set enabled(x) {", " ;", " }", "});", ].join("\n")); ok.deepEqual(issue836.names, ['enabled', 'x']); } function source_map(js) { var source_map = UglifyJS.SourceMap(); var stream = UglifyJS.OutputStream({ source_map: source_map }); var parsed = UglifyJS.parse(js); parsed.print(stream); return JSON.parse(source_map.toString()); } // Run standalone if (module.parent === null) { module.exports(); } UglifyJS2-2.8.29/test/ufuzz.js000066400000000000000000001161201312030606600160700ustar00rootroot00000000000000// ufuzz.js // derived from https://github.com/qfox/uglyfuzzer by Peter van der Zee "use strict"; // check both CLI and file modes of nodejs (!). See #1695 for details. and the various settings of uglify. // bin/uglifyjs s.js -c && bin/uglifyjs s.js -c passes=3 && bin/uglifyjs s.js -c passes=3 -m // cat s.js | node && node s.js && bin/uglifyjs s.js -c | node && bin/uglifyjs s.js -c passes=3 | node && bin/uglifyjs s.js -c passes=3 -m | node // workaround for tty output truncation upon process.exit() [process.stdout, process.stderr].forEach(function(stream){ if (stream._handle && stream._handle.setBlocking) stream._handle.setBlocking(true); }); var UglifyJS = require(".."); var randomBytes = require("crypto").randomBytes; var sandbox = require("./sandbox"); var MAX_GENERATED_TOPLEVELS_PER_RUN = 1; var MAX_GENERATION_RECURSION_DEPTH = 12; var INTERVAL_COUNT = 100; var STMT_ARG_TO_ID = Object.create(null); var STMTS_TO_USE = []; function STMT_(name) { return STMT_ARG_TO_ID[name] = STMTS_TO_USE.push(STMTS_TO_USE.length) - 1; } var STMT_BLOCK = STMT_("block"); var STMT_IF_ELSE = STMT_("ifelse"); var STMT_DO_WHILE = STMT_("dowhile"); var STMT_WHILE = STMT_("while"); var STMT_FOR_LOOP = STMT_("forloop"); var STMT_FOR_IN = STMT_("forin"); var STMT_SEMI = STMT_("semi"); var STMT_EXPR = STMT_("expr"); var STMT_SWITCH = STMT_("switch"); var STMT_VAR = STMT_("var"); var STMT_RETURN_ETC = STMT_("stop"); var STMT_FUNC_EXPR = STMT_("funcexpr"); var STMT_TRY = STMT_("try"); var STMT_C = STMT_("c"); var STMT_FIRST_LEVEL_OVERRIDE = -1; var STMT_SECOND_LEVEL_OVERRIDE = -1; var STMT_COUNT_FROM_GLOBAL = true; // count statement depth from nearest function scope or just global scope? var num_iterations = +process.argv[2] || 1/0; var verbose = false; // log every generated test var verbose_interval = false; // log every 100 generated tests var use_strict = false; var catch_redef = require.main === module; var generate_directive = require.main === module; for (var i = 2; i < process.argv.length; ++i) { switch (process.argv[i]) { case '-v': verbose = true; break; case '-V': verbose_interval = true; break; case '-t': MAX_GENERATED_TOPLEVELS_PER_RUN = +process.argv[++i]; if (!MAX_GENERATED_TOPLEVELS_PER_RUN) throw new Error('Must generate at least one toplevel per run'); break; case '-r': MAX_GENERATION_RECURSION_DEPTH = +process.argv[++i]; if (!MAX_GENERATION_RECURSION_DEPTH) throw new Error('Recursion depth must be at least 1'); break; case '-s1': var name = process.argv[++i]; STMT_FIRST_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name]; if (!(STMT_FIRST_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list'); break; case '-s2': var name = process.argv[++i]; STMT_SECOND_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name]; if (!(STMT_SECOND_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list'); break; case '--no-catch-redef': catch_redef = false; break; case '--no-directive': generate_directive = false; break; case '--use-strict': use_strict = true; break; case '--stmt-depth-from-func': STMT_COUNT_FROM_GLOBAL = false; break; case '--only-stmt': STMTS_TO_USE = process.argv[++i].split(',').map(function(name){ return STMT_ARG_TO_ID[name]; }); break; case '--without-stmt': // meh. it runs once it's fine. process.argv[++i].split(',').forEach(function(name){ var omit = STMT_ARG_TO_ID[name]; STMTS_TO_USE = STMTS_TO_USE.filter(function(id){ return id !== omit; }) }); break; case '--help': case '-h': case '-?': console.log('** UglifyJS fuzzer help **'); console.log('Valid options (optional):'); console.log(': generate this many cases (if used must be first arg)'); console.log('-v: print every generated test case'); console.log('-V: print every 100th generated test case'); console.log('-t : generate this many toplevels per run (more take longer)'); console.log('-r : maximum recursion depth for generator (higher takes longer)'); console.log('-s1 : force the first level statement to be this one (see list below)'); console.log('-s2 : force the second level statement to be this one (see list below)'); console.log('--no-catch-redef: do not redefine catch variables'); console.log('--no-directive: do not generate directives'); console.log('--use-strict: generate "use strict"'); console.log('--stmt-depth-from-func: reset statement depth counter at each function, counts from global otherwise'); console.log('--only-stmt : a comma delimited white list of statements that may be generated'); console.log('--without-stmt : a comma delimited black list of statements never to generate'); console.log('List of accepted statement names: ' + Object.keys(STMT_ARG_TO_ID)); console.log('** UglifyJS fuzzer exiting **'); return 0; default: // first arg may be a number. if (i > 2 || !parseInt(process.argv[i], 10)) throw new Error('Unknown argument[' + process.argv[i] + ']; see -h for help'); } } var VALUES = [ '""', 'true', 'false', ' /[a2][^e]+$/ ', '(-1)', '(-2)', '(-3)', '(-4)', '(-5)', '0', '1', '2', '3', '4', '5', '22', '-0', // 0/-0 !== 0 '23..toString()', '24 .toString()', '25. ', '0x26.toString()', 'NaN', 'undefined', 'Infinity', 'null', '[]', '[,0][1]', // an array with elisions... but this is always false '([,0].length === 2)', // an array with elisions... this is always true '({})', // wrapped the object causes too many syntax errors in statements '"foo"', '"bar"', '"undefined"', '"object"', '"number"', '"function"', ]; var BINARY_OPS_NO_COMMA = [ ' + ', // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors) ' - ', '/', '*', '&', '|', '^', '<', '<=', '>', '>=', '==', '===', '!=', '!==', '<<', '>>', '>>>', '%', '&&', '||', '^' ]; var BINARY_OPS = [','].concat(BINARY_OPS_NO_COMMA); var ASSIGNMENTS = [ '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '=', '+=', '+=', '+=', '+=', '+=', '+=', '+=', '+=', '+=', '+=', '-=', '*=', '/=', '&=', '|=', '^=', '<<=', '>>=', '>>>=', '%=', ]; var UNARY_SAFE = [ '+', '-', '~', '!', 'void ', 'delete ', ]; var UNARY_POSTFIX = [ '++', '--', ]; var UNARY_PREFIX = UNARY_POSTFIX.concat(UNARY_SAFE); var NO_COMMA = true; var COMMA_OK = false; var MAYBE = true; var MANDATORY = false; var CAN_THROW = true; var CANNOT_THROW = false; var CAN_BREAK = true; var CANNOT_BREAK = false; var CAN_CONTINUE = true; var CANNOT_CONTINUE = false; var CAN_RETURN = false; var CANNOT_RETURN = true; var NOT_GLOBAL = true; var IN_GLOBAL = true; var ANY_TYPE = false; var NO_DECL = true; var DONT_STORE = true; var VAR_NAMES = [ 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', // prevent redeclaring this, avoid assigning to this 'foo', 'foo', 'bar', 'bar', 'undefined', 'NaN', 'Infinity', 'arguments', 'Math', 'parseInt', ]; var INITIAL_NAMES_LEN = VAR_NAMES.length; var TYPEOF_OUTCOMES = [ 'function', 'undefined', 'string', 'number', 'object', 'boolean', 'special', 'unknown', 'symbol', 'crap' ]; var unique_vars = []; var loops = 0; var funcs = 0; var labels = 10000; function rng(max) { var r = randomBytes(2).readUInt16LE(0) / 65536; return Math.floor(max * r); } function strictMode() { return use_strict && rng(4) == 0 ? '"use strict";' : ''; } function createTopLevelCode() { VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list unique_vars.length = 0; loops = 0; funcs = 0; return [ strictMode(), 'var a = 100, b = 10, c = 0;', rng(2) == 0 ? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0) : createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, IN_GLOBAL, ANY_TYPE, CANNOT_THROW, 0), 'console.log(null, a, b, c);' // preceding `null` makes for a cleaner output (empty string still shows up etc) ].join('\n'); } function createFunctions(n, recurmax, inGlobal, noDecl, canThrow, stmtDepth) { if (--recurmax < 0) { return ';'; } var s = ''; while (n-- > 0) { s += createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) + '\n'; } return s; } function createParams() { var params = []; for (var n = rng(4); --n >= 0;) { params.push(createVarName(MANDATORY)); } return params.join(', '); } function createArgs() { var args = []; for (var n = rng(4); --n >= 0;) { args.push(createValue()); } return args.join(', '); } function filterDirective(s) { if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ';' + s[2]; return s; } function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) { if (--recurmax < 0) { return ';'; } if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0; var func = funcs++; var namesLenBefore = VAR_NAMES.length; var name; if (inGlobal || rng(5) > 0) name = 'f' + func; else { unique_vars.push('a', 'b', 'c'); name = createVarName(MANDATORY, noDecl); unique_vars.length -= 3; } var s = [ 'function ' + name + '(' + createParams() + '){', strictMode() ]; if (rng(5) === 0) { // functions with functions. lower the recursion to prevent a mess. s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth)); } else { // functions with statements s.push(createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)); } s.push('}', ''); s = filterDirective(s).join('\n'); VAR_NAMES.length = namesLenBefore; if (noDecl) s = 'var ' + createVarName(MANDATORY) + ' = ' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ');'; // avoid "function statements" (decl inside statements) else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');'; return s; } function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { if (--recurmax < 0) { return ';'; } var s = ''; while (--n > 0) { s += createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '\n'; } return s; } function enableLoopControl(flag, defaultValue) { return Array.isArray(flag) && flag.indexOf("") < 0 ? flag.concat("") : flag || defaultValue; } function createLabel(canBreak, canContinue) { var label; if (rng(10) < 3) { label = ++labels; if (Array.isArray(canBreak)) { canBreak = canBreak.slice(); } else { canBreak = canBreak ? [ "" ] : []; } canBreak.push(label); if (Array.isArray(canContinue)) { canContinue = canContinue.slice(); } else { canContinue = canContinue ? [ "" ] : []; } canContinue.push(label); } return { break: canBreak, continue: canContinue, target: label ? "L" + label + ": " : "" }; } function getLabel(label) { if (!Array.isArray(label)) return ""; label = label[rng(label.length)]; return label && " L" + label; } function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, target) { ++stmtDepth; var loop = ++loops; if (--recurmax < 0) { return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ';'; } // allow to forcefully generate certain structures at first or second recursion level if (target === undefined) { if (stmtDepth === 1 && STMT_FIRST_LEVEL_OVERRIDE >= 0) target = STMT_FIRST_LEVEL_OVERRIDE; else if (stmtDepth === 2 && STMT_SECOND_LEVEL_OVERRIDE >= 0) target = STMT_SECOND_LEVEL_OVERRIDE; else target = STMTS_TO_USE[rng(STMTS_TO_USE.length)]; } switch (target) { case STMT_BLOCK: var label = createLabel(canBreak); return label.target + '{' + createStatements(rng(5) + 1, recurmax, canThrow, label.break, canContinue, cannotReturn, stmtDepth) + '}'; case STMT_IF_ELSE: return 'if (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + (rng(2) === 1 ? ' else ' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) : ''); case STMT_DO_WHILE: var label = createLabel(canBreak, canContinue); canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK); canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE); return '{var brake' + loop + ' = 5; ' + label.target + 'do {' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '} while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0);}'; case STMT_WHILE: var label = createLabel(canBreak, canContinue); canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK); canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE); return '{var brake' + loop + ' = 5; ' + label.target + 'while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0)' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '}'; case STMT_FOR_LOOP: var label = createLabel(canBreak, canContinue); canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK); canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE); return label.target + 'for (var brake' + loop + ' = 5; (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && brake' + loop + ' > 0; --brake' + loop + ')' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth); case STMT_FOR_IN: var label = createLabel(canBreak, canContinue); canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK); canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE); var optElementVar = ''; if (rng(5) > 1) { optElementVar = 'c = 1 + c; var ' + createVarName(MANDATORY) + ' = expr' + loop + '[key' + loop + ']; '; } return '{var expr' + loop + ' = ' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + '; ' + label.target + ' for (var key' + loop + ' in expr' + loop + ') {' + optElementVar + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '}}'; case STMT_SEMI: return use_strict && rng(20) === 0 ? '"use strict";' : ';'; case STMT_EXPR: return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ';'; case STMT_SWITCH: // note: case args are actual expressions // note: default does not _need_ to be last return 'switch (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') { ' + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '}'; case STMT_VAR: switch (rng(3)) { case 0: unique_vars.push('c'); var name = createVarName(MANDATORY); unique_vars.pop(); return 'var ' + name + ';'; case 1: // initializer can only have one expression unique_vars.push('c'); var name = createVarName(MANDATORY); unique_vars.pop(); return 'var ' + name + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';'; default: // initializer can only have one expression unique_vars.push('c'); var n1 = createVarName(MANDATORY); var n2 = createVarName(MANDATORY); unique_vars.pop(); return 'var ' + n1 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ', ' + n2 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';'; } case STMT_RETURN_ETC: switch (rng(8)) { case 0: case 1: case 2: case 3: if (canBreak && rng(5) === 0) return 'break' + getLabel(canBreak) + ';'; if (canContinue && rng(5) === 0) return 'continue' + getLabel(canContinue) + ';'; if (cannotReturn) return createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';'; if (rng(3) == 0) return '/*3*/return;'; return 'return ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';'; case 4: // this is actually more like a parser test, but perhaps it hits some dead code elimination traps // must wrap in curlies to prevent orphaned `else` statement // note: you can't `throw` without an expression so don't put a `throw` option in this case if (cannotReturn) return createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';'; return '{ /*2*/ return\n' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + '}'; default: // must wrap in curlies to prevent orphaned `else` statement if (canThrow && rng(5) === 0) return '{ throw ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + '}'; if (cannotReturn) return createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';'; return '{ return ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + '}'; } case STMT_FUNC_EXPR: // "In non-strict mode code, functions can only be declared at top level, inside a block, or ..." // (dont both with func decls in `if`; it's only a parser thing because you cant call them without a block) return '{' + createFunction(recurmax, NOT_GLOBAL, NO_DECL, canThrow, stmtDepth) + '}'; case STMT_TRY: // catch var could cause some problems // note: the "blocks" are syntactically mandatory for try/catch/finally var n = rng(3); // 0=only catch, 1=only finally, 2=catch+finally var s = 'try {' + createStatement(recurmax, n === 1 ? CANNOT_THROW : CAN_THROW, canBreak, canContinue, cannotReturn, stmtDepth) + ' }'; if (n !== 1) { // the catch var should only be accessible in the catch clause... // we have to do go through some trouble here to prevent leaking it var nameLenBefore = VAR_NAMES.length; var catchName = createVarName(MANDATORY); var freshCatchName = VAR_NAMES.length !== nameLenBefore; if (!catch_redef) unique_vars.push(catchName); s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }'; // remove catch name if (!catch_redef) unique_vars.pop(); if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); } if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }'; return s; case STMT_C: return 'c = c + 1;'; default: throw 'no'; } } function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { var hadDefault = false; var s = ['']; canBreak = enableLoopControl(canBreak, CAN_BREAK); while (n-- > 0) { //hadDefault = n > 0; // disables weird `default` clause positioning (use when handling destabilizes) if (hadDefault || rng(5) > 0) { s.push( 'case ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ':', createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), rng(10) > 0 ? ' break;' : '/* fall-through */', '' ); } else { hadDefault = true; s.push( 'default:', createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), '' ); } } return s.join('\n'); } function createExpression(recurmax, noComma, stmtDepth, canThrow) { if (--recurmax < 0) { return '(c = 1 + c, ' + createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; // note: should return a simple non-recursing expression value! } // since `a` and `b` are our canaries we want them more frequently than other expressions (1/3rd chance of a canary) switch (rng(6)) { case 0: return '(a++ + (' + _createExpression(recurmax, noComma, stmtDepth, canThrow) + '))'; case 1: return '((--b) + (' + _createExpression(recurmax, noComma, stmtDepth, canThrow) + '))'; case 2: return '((c = c + 1) + (' + _createExpression(recurmax, noComma, stmtDepth, canThrow) + '))'; // c only gets incremented default: return '(' + _createExpression(recurmax, noComma, stmtDepth, canThrow) + ')'; } } function _createExpression(recurmax, noComma, stmtDepth, canThrow) { var p = 0; switch (rng(_createExpression.N)) { case p++: case p++: return createUnaryPrefix() + (rng(2) === 1 ? 'a' : 'b'); case p++: case p++: return (rng(2) === 1 ? 'a' : 'b') + createUnaryPostfix(); case p++: case p++: // parens needed because assignments aren't valid unless they're the left-most op(s) in an expression return 'b ' + createAssignment() + ' a'; case p++: case p++: return rng(2) + ' === 1 ? a : b'; case p++: case p++: return createValue(); case p++: return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow); case p++: return createExpression(recurmax, noComma, stmtDepth, canThrow) + '?' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ':' + createExpression(recurmax, noComma, stmtDepth, canThrow); case p++: case p++: var nameLenBefore = VAR_NAMES.length; unique_vars.push('c'); var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that. unique_vars.pop(); var s = []; switch (rng(5)) { case 0: s.push( '(function ' + name + '(){', strictMode(), createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), '})()' ); break; case 1: s.push( '+function ' + name + '(){', strictMode(), createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), '}()' ); break; case 2: s.push( '!function ' + name + '(){', strictMode(), createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), '}()' ); break; case 3: s.push( 'void function ' + name + '(){', strictMode(), createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), '}()' ); break; default: var instantiate = rng(4) ? 'new ' : ''; s.push( instantiate + 'function ' + name + '(){', strictMode() ); if (instantiate) for (var i = rng(4); --i >= 0;) { if (rng(2)) s.push('this.' + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';'); else s.push('this[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']' + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';'); } s.push( createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), '}' ); break; } VAR_NAMES.length = nameLenBefore; return filterDirective(s).join('\n'); case p++: case p++: return createTypeofExpr(recurmax, stmtDepth, canThrow); case p++: case p++: // more like a parser test but perhaps comment nodes mess up the analysis? // note: parens not needed for post-fix (since that's the default when ambiguous) // for prefix ops we need parens to prevent accidental syntax errors. switch (rng(6)) { case 0: return 'a/* ignore */++'; case 1: return 'b/* ignore */--'; case 2: return '++/* ignore */a'; case 3: return '--/* ignore */b'; case 4: // only groups that wrap a single variable return a "Reference", so this is still valid. // may just be a parser edge case that is invisible to uglify... return '--(b)'; case 5: // classic 0.3-0.1 case; 1-0.1-0.1-0.1 is not 0.7 :) return 'b + 1-0.1-0.1-0.1'; default: return '--/* ignore */b'; } case p++: case p++: return createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow); case p++: case p++: return createUnarySafePrefix() + '(' + createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; case p++: return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || a || 3).toString() "; case p++: return " /[abc4]/.test(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) "; case p++: return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || " + rng(10) + ").toString()[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "] "; case p++: return createArrayLiteral(recurmax, stmtDepth, canThrow); case p++: return createObjectLiteral(recurmax, stmtDepth, canThrow); case p++: return createArrayLiteral(recurmax, stmtDepth, canThrow) + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']'; case p++: return createObjectLiteral(recurmax, stmtDepth, canThrow) + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']'; case p++: return createArrayLiteral(recurmax, stmtDepth, canThrow) + '.' + getDotKey(); case p++: return createObjectLiteral(recurmax, stmtDepth, canThrow) + '.' + getDotKey(); case p++: var name = getVarName(); return name + ' && ' + name + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']'; case p++: var name = getVarName(); return name + ' && ' + name + '.' + getDotKey(); } _createExpression.N = p; return _createExpression(recurmax, noComma, stmtDepth, canThrow); } function createArrayLiteral(recurmax, stmtDepth, canThrow) { recurmax--; var arr = "["; for (var i = rng(6); --i >= 0;) { // in rare cases produce an array hole element var element = rng(20) ? createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) : ""; arr += element + ", "; } return arr + "]"; } var SAFE_KEYS = [ "length", "foo", "a", "b", "c", "undefined", "null", "NaN", "Infinity", "in", "var", ]; var KEYS = [ "''", '"\t"', '"-2"', "0", "1.5", "3", ].concat(SAFE_KEYS); function getDotKey(assign) { var key; do { key = SAFE_KEYS[rng(SAFE_KEYS.length)]; } while (assign && key == "length"); return key; } function createAccessor(recurmax, stmtDepth, canThrow) { var namesLenBefore = VAR_NAMES.length; var s; var prop1 = getDotKey(); if (rng(2) == 0) { s = [ 'get ' + prop1 + '(){', strictMode(), createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC), '},' ]; } else { var prop2; do { prop2 = getDotKey(); } while (prop1 == prop2); s = [ 'set ' + prop1 + '(' + createVarName(MANDATORY) + '){', strictMode(), createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), 'this.' + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ';', '},' ]; } VAR_NAMES.length = namesLenBefore; return filterDirective(s).join('\n'); } function createObjectLiteral(recurmax, stmtDepth, canThrow) { recurmax--; var obj = ['({']; for (var i = rng(6); --i >= 0;) { if (rng(20) == 0) { obj.push(createAccessor(recurmax, stmtDepth, canThrow)); } else { var key = KEYS[rng(KEYS.length)]; obj.push(key + ':(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + '),'); } } obj.push('})'); return obj.join('\n'); } function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) { recurmax = 3; // note that this generates 2^recurmax expression parts... make sure to cap it return _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow); } function _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) { return '(' + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + createBinaryOp(noComma) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; } function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) { // intentionally generate more hardcore ops if (--recurmax < 0) return createValue(); var assignee, expr; switch (rng(30)) { case 0: return '(c = c + 1, ' + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; case 1: return '(' + createUnarySafePrefix() + '(' + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + '))'; case 2: assignee = getVarName(); return '(' + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; case 3: assignee = getVarName(); expr = '(' + assignee + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']' + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')'; case 4: assignee = getVarName(); expr = '(' + assignee + '.' + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')'; return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')'; default: return _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow); } } function createTypeofExpr(recurmax, stmtDepth, canThrow) { switch (rng(8)) { case 0: return '(typeof ' + createVarName(MANDATORY, DONT_STORE) + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")'; case 1: return '(typeof ' + createVarName(MANDATORY, DONT_STORE) + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")'; case 2: return '(typeof ' + createVarName(MANDATORY, DONT_STORE) + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")'; case 3: return '(typeof ' + createVarName(MANDATORY, DONT_STORE) + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")'; case 4: return '(typeof ' + createVarName(MANDATORY, DONT_STORE) + ')'; default: return '(typeof ' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')'; } } function createValue() { return VALUES[rng(VALUES.length)]; } function createBinaryOp(noComma) { if (noComma) return BINARY_OPS_NO_COMMA[rng(BINARY_OPS_NO_COMMA.length)]; return BINARY_OPS[rng(BINARY_OPS.length)]; } function createAssignment() { return ASSIGNMENTS[rng(ASSIGNMENTS.length)]; } function createUnarySafePrefix() { return UNARY_SAFE[rng(UNARY_SAFE.length)]; } function createUnaryPrefix() { return UNARY_PREFIX[rng(UNARY_PREFIX.length)]; } function createUnaryPostfix() { return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)]; } function getVarName() { // try to get a generated name reachable from current scope. default to just `a` return VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)] || 'a'; } function createVarName(maybe, dontStore) { if (!maybe || rng(2)) { var suffix = rng(3); var name; do { name = VAR_NAMES[rng(VAR_NAMES.length)]; if (suffix) name += '_' + suffix; } while (unique_vars.indexOf(name) >= 0); if (suffix && !dontStore) VAR_NAMES.push(name); return name; } return ''; } if (require.main !== module) { exports.createTopLevelCode = createTopLevelCode; exports.num_iterations = num_iterations; return; } function try_beautify(code, result) { try { var beautified = UglifyJS.minify(code, { fromString: true, compress: false, mangle: false, output: { beautify: true, bracketize: true, }, }).code; if (sandbox.same_stdout(sandbox.run_code(beautified), result)) { console.log("// (beautified)"); console.log(beautified); return; } } catch (e) { console.log("// !!! beautify failed !!!"); console.log(e.stack); } console.log("//"); console.log(code); } function infer_options(ctor) { try { ctor({ 0: 0 }); } catch (e) { return e.defs; } } var default_options = { compress: infer_options(UglifyJS.Compressor), mangle: { "cache": null, "eval": false, "ie8": false, "keep_fnames": false, "toplevel": false, }, output: infer_options(UglifyJS.OutputStream), }; function log_suspects(minify_options, component) { var options = component in minify_options ? minify_options[component] : true; if (!options) return; options = UglifyJS.defaults(options, default_options[component]); var suspects = Object.keys(default_options[component]).filter(function(name) { if (options[name]) { var m = JSON.parse(JSON.stringify(minify_options)); var o = JSON.parse(JSON.stringify(options)); o[name] = false; m[component] = o; try { var r = sandbox.run_code(UglifyJS.minify(original_code, m).code); return sandbox.same_stdout(original_result, r); } catch (e) { console.log("Error testing options." + component + "." + name); console.log(e); } } }); if (suspects.length > 0) { console.log("Suspicious", component, "options:"); suspects.forEach(function(name) { console.log(" " + name); }); console.log(); } } function log(options) { if (!ok) console.log('\n\n\n\n\n\n!!!!!!!!!!\n\n\n'); console.log("//============================================================="); if (!ok) console.log("// !!!!!! Failed... round", round); console.log("// original code"); try_beautify(original_code, original_result); console.log(); console.log(); console.log("//-------------------------------------------------------------"); if (typeof uglify_code == "string") { console.log("// uglified code"); try_beautify(uglify_code, uglify_result); console.log(); console.log(); console.log("original result:"); console.log(original_result); console.log("uglified result:"); console.log(uglify_result); } else { console.log("// !!! uglify failed !!!"); console.log(uglify_code.stack); if (typeof original_result != "string") { console.log(); console.log(); console.log("original stacktrace:"); console.log(original_result.stack); } } console.log("minify(options):"); options = JSON.parse(options); console.log(options); console.log(); if (!ok && typeof uglify_code == "string") { Object.keys(default_options).forEach(log_suspects.bind(null, options)); console.log("!!!!!! Failed... round", round); } } var fallback_options = [ JSON.stringify({ compress: false, mangle: false }) ]; var minify_options = require("./ufuzz.json").map(function(options) { options.fromString = true; return JSON.stringify(options); }); var original_code, original_result; var uglify_code, uglify_result, ok; for (var round = 1; round <= num_iterations; round++) { process.stdout.write(round + " of " + num_iterations + "\r"); original_code = createTopLevelCode(); original_result = sandbox.run_code(original_code); (typeof original_result != "string" ? fallback_options : minify_options).forEach(function(options) { try { uglify_code = UglifyJS.minify(original_code, JSON.parse(options)).code; } catch (e) { uglify_code = e; } ok = typeof uglify_code == "string"; if (ok) { uglify_result = sandbox.run_code(uglify_code); ok = sandbox.same_stdout(original_result, uglify_result); } else if (typeof original_result != "string") { ok = uglify_code.name == original_result.name; } if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options); else if (typeof original_result != "string") { console.log("//============================================================="); console.log("// original code"); try_beautify(original_code, original_result); console.log(); console.log(); console.log("original result:"); console.log(original_result); console.log(); } if (!ok && isFinite(num_iterations)) { console.log(); process.exit(1); } }); } console.log(); UglifyJS2-2.8.29/test/ufuzz.json000066400000000000000000000012371312030606600164270ustar00rootroot00000000000000[ { "compress": false, "mangle": false, "output": { "beautify": true, "bracketize": true } }, { "compress": false }, { "compress": { "warnings": false }, "mangle": false }, { "compress": { "warnings": false } }, { "compress": { "toplevel": true, "warnings": false }, "mangle": { "toplevel": true } }, { "compress": { "keep_fargs": false, "passes": 3, "warnings": false } } ] UglifyJS2-2.8.29/tools/000077500000000000000000000000001312030606600145275ustar00rootroot00000000000000UglifyJS2-2.8.29/tools/domprops.json000066400000000000000000004267661312030606600173120ustar00rootroot00000000000000{ "props": [ "$&", "$'", "$*", "$+", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$_", "$`", "$input", "@@iterator", "ABORT_ERR", "ACTIVE", "ACTIVE_ATTRIBUTES", "ACTIVE_TEXTURE", "ACTIVE_UNIFORMS", "ADDITION", "ALIASED_LINE_WIDTH_RANGE", "ALIASED_POINT_SIZE_RANGE", "ALLOW_KEYBOARD_INPUT", "ALLPASS", "ALPHA", "ALPHA_BITS", "ALT_MASK", "ALWAYS", "ANY_TYPE", "ANY_UNORDERED_NODE_TYPE", "ARRAY_BUFFER", "ARRAY_BUFFER_BINDING", "ATTACHED_SHADERS", "ATTRIBUTE_NODE", "AT_TARGET", "AddSearchProvider", "AnalyserNode", "AnimationEvent", "AnonXMLHttpRequest", "ApplicationCache", "ApplicationCacheErrorEvent", "Array", "ArrayBuffer", "Attr", "Audio", "AudioBuffer", "AudioBufferSourceNode", "AudioContext", "AudioDestinationNode", "AudioListener", "AudioNode", "AudioParam", "AudioProcessingEvent", "AudioStreamTrack", "AutocompleteErrorEvent", "BACK", "BAD_BOUNDARYPOINTS_ERR", "BANDPASS", "BLEND", "BLEND_COLOR", "BLEND_DST_ALPHA", "BLEND_DST_RGB", "BLEND_EQUATION", "BLEND_EQUATION_ALPHA", "BLEND_EQUATION_RGB", "BLEND_SRC_ALPHA", "BLEND_SRC_RGB", "BLUE_BITS", "BLUR", "BOOL", "BOOLEAN_TYPE", "BOOL_VEC2", "BOOL_VEC3", "BOOL_VEC4", "BOTH", "BROWSER_DEFAULT_WEBGL", "BUBBLING_PHASE", "BUFFER_SIZE", "BUFFER_USAGE", "BYTE", "BYTES_PER_ELEMENT", "BarProp", "BaseHref", "BatteryManager", "BeforeLoadEvent", "BeforeUnloadEvent", "BiquadFilterNode", "Blob", "BlobEvent", "Boolean", "CAPTURING_PHASE", "CCW", "CDATASection", "CDATA_SECTION_NODE", "CHANGE", "CHARSET_RULE", "CHECKING", "CLAMP_TO_EDGE", "CLICK", "CLOSED", "CLOSING", "COLOR_ATTACHMENT0", "COLOR_BUFFER_BIT", "COLOR_CLEAR_VALUE", "COLOR_WRITEMASK", "COMMENT_NODE", "COMPILE_STATUS", "COMPRESSED_RGBA_S3TC_DXT1_EXT", "COMPRESSED_RGBA_S3TC_DXT3_EXT", "COMPRESSED_RGBA_S3TC_DXT5_EXT", "COMPRESSED_RGB_S3TC_DXT1_EXT", "COMPRESSED_TEXTURE_FORMATS", "CONNECTING", "CONSTANT_ALPHA", "CONSTANT_COLOR", "CONSTRAINT_ERR", "CONTEXT_LOST_WEBGL", "CONTROL_MASK", "COUNTER_STYLE_RULE", "CSS", "CSS2Properties", "CSSCharsetRule", "CSSConditionRule", "CSSCounterStyleRule", "CSSFontFaceRule", "CSSFontFeatureValuesRule", "CSSGroupingRule", "CSSImportRule", "CSSKeyframeRule", "CSSKeyframesRule", "CSSMediaRule", "CSSMozDocumentRule", "CSSNameSpaceRule", "CSSPageRule", "CSSPrimitiveValue", "CSSRule", "CSSRuleList", "CSSStyleDeclaration", "CSSStyleRule", "CSSStyleSheet", "CSSSupportsRule", "CSSUnknownRule", "CSSValue", "CSSValueList", "CSSVariablesDeclaration", "CSSVariablesRule", "CSSViewportRule", "CSS_ATTR", "CSS_CM", "CSS_COUNTER", "CSS_CUSTOM", "CSS_DEG", "CSS_DIMENSION", "CSS_EMS", "CSS_EXS", "CSS_FILTER_BLUR", "CSS_FILTER_BRIGHTNESS", "CSS_FILTER_CONTRAST", "CSS_FILTER_CUSTOM", "CSS_FILTER_DROP_SHADOW", "CSS_FILTER_GRAYSCALE", "CSS_FILTER_HUE_ROTATE", "CSS_FILTER_INVERT", "CSS_FILTER_OPACITY", "CSS_FILTER_REFERENCE", "CSS_FILTER_SATURATE", "CSS_FILTER_SEPIA", "CSS_GRAD", "CSS_HZ", "CSS_IDENT", "CSS_IN", "CSS_INHERIT", "CSS_KHZ", "CSS_MATRIX", "CSS_MATRIX3D", "CSS_MM", "CSS_MS", "CSS_NUMBER", "CSS_PC", "CSS_PERCENTAGE", "CSS_PERSPECTIVE", "CSS_PRIMITIVE_VALUE", "CSS_PT", "CSS_PX", "CSS_RAD", "CSS_RECT", "CSS_RGBCOLOR", "CSS_ROTATE", "CSS_ROTATE3D", "CSS_ROTATEX", "CSS_ROTATEY", "CSS_ROTATEZ", "CSS_S", "CSS_SCALE", "CSS_SCALE3D", "CSS_SCALEX", "CSS_SCALEY", "CSS_SCALEZ", "CSS_SKEW", "CSS_SKEWX", "CSS_SKEWY", "CSS_STRING", "CSS_TRANSLATE", "CSS_TRANSLATE3D", "CSS_TRANSLATEX", "CSS_TRANSLATEY", "CSS_TRANSLATEZ", "CSS_UNKNOWN", "CSS_URI", "CSS_VALUE_LIST", "CSS_VH", "CSS_VMAX", "CSS_VMIN", "CSS_VW", "CULL_FACE", "CULL_FACE_MODE", "CURRENT_PROGRAM", "CURRENT_VERTEX_ATTRIB", "CUSTOM", "CW", "CanvasGradient", "CanvasPattern", "CanvasRenderingContext2D", "CaretPosition", "ChannelMergerNode", "ChannelSplitterNode", "CharacterData", "ClientRect", "ClientRectList", "Clipboard", "ClipboardEvent", "CloseEvent", "Collator", "CommandEvent", "Comment", "CompositionEvent", "Console", "Controllers", "ConvolverNode", "Counter", "Crypto", "CryptoKey", "CustomEvent", "DATABASE_ERR", "DATA_CLONE_ERR", "DATA_ERR", "DBLCLICK", "DECR", "DECR_WRAP", "DELETE_STATUS", "DEPTH_ATTACHMENT", "DEPTH_BITS", "DEPTH_BUFFER_BIT", "DEPTH_CLEAR_VALUE", "DEPTH_COMPONENT", "DEPTH_COMPONENT16", "DEPTH_FUNC", "DEPTH_RANGE", "DEPTH_STENCIL", "DEPTH_STENCIL_ATTACHMENT", "DEPTH_TEST", "DEPTH_WRITEMASK", "DIRECTION_DOWN", "DIRECTION_LEFT", "DIRECTION_RIGHT", "DIRECTION_UP", "DISABLED", "DISPATCH_REQUEST_ERR", "DITHER", "DOCUMENT_FRAGMENT_NODE", "DOCUMENT_NODE", "DOCUMENT_POSITION_CONTAINED_BY", "DOCUMENT_POSITION_CONTAINS", "DOCUMENT_POSITION_DISCONNECTED", "DOCUMENT_POSITION_FOLLOWING", "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", "DOCUMENT_POSITION_PRECEDING", "DOCUMENT_TYPE_NODE", "DOMCursor", "DOMError", "DOMException", "DOMImplementation", "DOMImplementationLS", "DOMMatrix", "DOMMatrixReadOnly", "DOMParser", "DOMPoint", "DOMPointReadOnly", "DOMQuad", "DOMRect", "DOMRectList", "DOMRectReadOnly", "DOMRequest", "DOMSTRING_SIZE_ERR", "DOMSettableTokenList", "DOMStringList", "DOMStringMap", "DOMTokenList", "DOMTransactionEvent", "DOM_DELTA_LINE", "DOM_DELTA_PAGE", "DOM_DELTA_PIXEL", "DOM_INPUT_METHOD_DROP", "DOM_INPUT_METHOD_HANDWRITING", "DOM_INPUT_METHOD_IME", "DOM_INPUT_METHOD_KEYBOARD", "DOM_INPUT_METHOD_MULTIMODAL", "DOM_INPUT_METHOD_OPTION", "DOM_INPUT_METHOD_PASTE", "DOM_INPUT_METHOD_SCRIPT", "DOM_INPUT_METHOD_UNKNOWN", "DOM_INPUT_METHOD_VOICE", "DOM_KEY_LOCATION_JOYSTICK", "DOM_KEY_LOCATION_LEFT", "DOM_KEY_LOCATION_MOBILE", "DOM_KEY_LOCATION_NUMPAD", "DOM_KEY_LOCATION_RIGHT", "DOM_KEY_LOCATION_STANDARD", "DOM_VK_0", "DOM_VK_1", "DOM_VK_2", "DOM_VK_3", "DOM_VK_4", "DOM_VK_5", "DOM_VK_6", "DOM_VK_7", "DOM_VK_8", "DOM_VK_9", "DOM_VK_A", "DOM_VK_ACCEPT", "DOM_VK_ADD", "DOM_VK_ALT", "DOM_VK_ALTGR", "DOM_VK_AMPERSAND", "DOM_VK_ASTERISK", "DOM_VK_AT", "DOM_VK_ATTN", "DOM_VK_B", "DOM_VK_BACKSPACE", "DOM_VK_BACK_QUOTE", "DOM_VK_BACK_SLASH", "DOM_VK_BACK_SPACE", "DOM_VK_C", "DOM_VK_CANCEL", "DOM_VK_CAPS_LOCK", "DOM_VK_CIRCUMFLEX", "DOM_VK_CLEAR", "DOM_VK_CLOSE_BRACKET", "DOM_VK_CLOSE_CURLY_BRACKET", "DOM_VK_CLOSE_PAREN", "DOM_VK_COLON", "DOM_VK_COMMA", "DOM_VK_CONTEXT_MENU", "DOM_VK_CONTROL", "DOM_VK_CONVERT", "DOM_VK_CRSEL", "DOM_VK_CTRL", "DOM_VK_D", "DOM_VK_DECIMAL", "DOM_VK_DELETE", "DOM_VK_DIVIDE", "DOM_VK_DOLLAR", "DOM_VK_DOUBLE_QUOTE", "DOM_VK_DOWN", "DOM_VK_E", "DOM_VK_EISU", "DOM_VK_END", "DOM_VK_ENTER", "DOM_VK_EQUALS", "DOM_VK_EREOF", "DOM_VK_ESCAPE", "DOM_VK_EXCLAMATION", "DOM_VK_EXECUTE", "DOM_VK_EXSEL", "DOM_VK_F", "DOM_VK_F1", "DOM_VK_F10", "DOM_VK_F11", "DOM_VK_F12", "DOM_VK_F13", "DOM_VK_F14", "DOM_VK_F15", "DOM_VK_F16", "DOM_VK_F17", "DOM_VK_F18", "DOM_VK_F19", "DOM_VK_F2", "DOM_VK_F20", "DOM_VK_F21", "DOM_VK_F22", "DOM_VK_F23", "DOM_VK_F24", "DOM_VK_F25", "DOM_VK_F26", "DOM_VK_F27", "DOM_VK_F28", "DOM_VK_F29", "DOM_VK_F3", "DOM_VK_F30", "DOM_VK_F31", "DOM_VK_F32", "DOM_VK_F33", "DOM_VK_F34", "DOM_VK_F35", "DOM_VK_F36", "DOM_VK_F4", "DOM_VK_F5", "DOM_VK_F6", "DOM_VK_F7", "DOM_VK_F8", "DOM_VK_F9", "DOM_VK_FINAL", "DOM_VK_FRONT", "DOM_VK_G", "DOM_VK_GREATER_THAN", "DOM_VK_H", "DOM_VK_HANGUL", "DOM_VK_HANJA", "DOM_VK_HASH", "DOM_VK_HELP", "DOM_VK_HK_TOGGLE", "DOM_VK_HOME", "DOM_VK_HYPHEN_MINUS", "DOM_VK_I", "DOM_VK_INSERT", "DOM_VK_J", "DOM_VK_JUNJA", "DOM_VK_K", "DOM_VK_KANA", "DOM_VK_KANJI", "DOM_VK_L", "DOM_VK_LEFT", "DOM_VK_LEFT_TAB", "DOM_VK_LESS_THAN", "DOM_VK_M", "DOM_VK_META", "DOM_VK_MODECHANGE", "DOM_VK_MULTIPLY", "DOM_VK_N", "DOM_VK_NONCONVERT", "DOM_VK_NUMPAD0", "DOM_VK_NUMPAD1", "DOM_VK_NUMPAD2", "DOM_VK_NUMPAD3", "DOM_VK_NUMPAD4", "DOM_VK_NUMPAD5", "DOM_VK_NUMPAD6", "DOM_VK_NUMPAD7", "DOM_VK_NUMPAD8", "DOM_VK_NUMPAD9", "DOM_VK_NUM_LOCK", "DOM_VK_O", "DOM_VK_OEM_1", "DOM_VK_OEM_102", "DOM_VK_OEM_2", "DOM_VK_OEM_3", "DOM_VK_OEM_4", "DOM_VK_OEM_5", "DOM_VK_OEM_6", "DOM_VK_OEM_7", "DOM_VK_OEM_8", "DOM_VK_OEM_COMMA", "DOM_VK_OEM_MINUS", "DOM_VK_OEM_PERIOD", "DOM_VK_OEM_PLUS", "DOM_VK_OPEN_BRACKET", "DOM_VK_OPEN_CURLY_BRACKET", "DOM_VK_OPEN_PAREN", "DOM_VK_P", "DOM_VK_PA1", "DOM_VK_PAGEDOWN", "DOM_VK_PAGEUP", "DOM_VK_PAGE_DOWN", "DOM_VK_PAGE_UP", "DOM_VK_PAUSE", "DOM_VK_PERCENT", "DOM_VK_PERIOD", "DOM_VK_PIPE", "DOM_VK_PLAY", "DOM_VK_PLUS", "DOM_VK_PRINT", "DOM_VK_PRINTSCREEN", "DOM_VK_PROCESSKEY", "DOM_VK_PROPERITES", "DOM_VK_Q", "DOM_VK_QUESTION_MARK", "DOM_VK_QUOTE", "DOM_VK_R", "DOM_VK_REDO", "DOM_VK_RETURN", "DOM_VK_RIGHT", "DOM_VK_S", "DOM_VK_SCROLL_LOCK", "DOM_VK_SELECT", "DOM_VK_SEMICOLON", "DOM_VK_SEPARATOR", "DOM_VK_SHIFT", "DOM_VK_SLASH", "DOM_VK_SLEEP", "DOM_VK_SPACE", "DOM_VK_SUBTRACT", "DOM_VK_T", "DOM_VK_TAB", "DOM_VK_TILDE", "DOM_VK_U", "DOM_VK_UNDERSCORE", "DOM_VK_UNDO", "DOM_VK_UNICODE", "DOM_VK_UP", "DOM_VK_V", "DOM_VK_VOLUME_DOWN", "DOM_VK_VOLUME_MUTE", "DOM_VK_VOLUME_UP", "DOM_VK_W", "DOM_VK_WIN", "DOM_VK_WINDOW", "DOM_VK_WIN_ICO_00", "DOM_VK_WIN_ICO_CLEAR", "DOM_VK_WIN_ICO_HELP", "DOM_VK_WIN_OEM_ATTN", "DOM_VK_WIN_OEM_AUTO", "DOM_VK_WIN_OEM_BACKTAB", "DOM_VK_WIN_OEM_CLEAR", "DOM_VK_WIN_OEM_COPY", "DOM_VK_WIN_OEM_CUSEL", "DOM_VK_WIN_OEM_ENLW", "DOM_VK_WIN_OEM_FINISH", "DOM_VK_WIN_OEM_FJ_JISHO", "DOM_VK_WIN_OEM_FJ_LOYA", "DOM_VK_WIN_OEM_FJ_MASSHOU", "DOM_VK_WIN_OEM_FJ_ROYA", "DOM_VK_WIN_OEM_FJ_TOUROKU", "DOM_VK_WIN_OEM_JUMP", "DOM_VK_WIN_OEM_PA1", "DOM_VK_WIN_OEM_PA2", "DOM_VK_WIN_OEM_PA3", "DOM_VK_WIN_OEM_RESET", "DOM_VK_WIN_OEM_WSCTRL", "DOM_VK_X", "DOM_VK_XF86XK_ADD_FAVORITE", "DOM_VK_XF86XK_APPLICATION_LEFT", "DOM_VK_XF86XK_APPLICATION_RIGHT", "DOM_VK_XF86XK_AUDIO_CYCLE_TRACK", "DOM_VK_XF86XK_AUDIO_FORWARD", "DOM_VK_XF86XK_AUDIO_LOWER_VOLUME", "DOM_VK_XF86XK_AUDIO_MEDIA", "DOM_VK_XF86XK_AUDIO_MUTE", "DOM_VK_XF86XK_AUDIO_NEXT", "DOM_VK_XF86XK_AUDIO_PAUSE", "DOM_VK_XF86XK_AUDIO_PLAY", "DOM_VK_XF86XK_AUDIO_PREV", "DOM_VK_XF86XK_AUDIO_RAISE_VOLUME", "DOM_VK_XF86XK_AUDIO_RANDOM_PLAY", "DOM_VK_XF86XK_AUDIO_RECORD", "DOM_VK_XF86XK_AUDIO_REPEAT", "DOM_VK_XF86XK_AUDIO_REWIND", "DOM_VK_XF86XK_AUDIO_STOP", "DOM_VK_XF86XK_AWAY", "DOM_VK_XF86XK_BACK", "DOM_VK_XF86XK_BACK_FORWARD", "DOM_VK_XF86XK_BATTERY", "DOM_VK_XF86XK_BLUE", "DOM_VK_XF86XK_BLUETOOTH", "DOM_VK_XF86XK_BOOK", "DOM_VK_XF86XK_BRIGHTNESS_ADJUST", "DOM_VK_XF86XK_CALCULATOR", "DOM_VK_XF86XK_CALENDAR", "DOM_VK_XF86XK_CD", "DOM_VK_XF86XK_CLOSE", "DOM_VK_XF86XK_COMMUNITY", "DOM_VK_XF86XK_CONTRAST_ADJUST", "DOM_VK_XF86XK_COPY", "DOM_VK_XF86XK_CUT", "DOM_VK_XF86XK_CYCLE_ANGLE", "DOM_VK_XF86XK_DISPLAY", "DOM_VK_XF86XK_DOCUMENTS", "DOM_VK_XF86XK_DOS", "DOM_VK_XF86XK_EJECT", "DOM_VK_XF86XK_EXCEL", "DOM_VK_XF86XK_EXPLORER", "DOM_VK_XF86XK_FAVORITES", "DOM_VK_XF86XK_FINANCE", "DOM_VK_XF86XK_FORWARD", "DOM_VK_XF86XK_FRAME_BACK", "DOM_VK_XF86XK_FRAME_FORWARD", "DOM_VK_XF86XK_GAME", "DOM_VK_XF86XK_GO", "DOM_VK_XF86XK_GREEN", "DOM_VK_XF86XK_HIBERNATE", "DOM_VK_XF86XK_HISTORY", "DOM_VK_XF86XK_HOME_PAGE", "DOM_VK_XF86XK_HOT_LINKS", "DOM_VK_XF86XK_I_TOUCH", "DOM_VK_XF86XK_KBD_BRIGHTNESS_DOWN", "DOM_VK_XF86XK_KBD_BRIGHTNESS_UP", "DOM_VK_XF86XK_KBD_LIGHT_ON_OFF", "DOM_VK_XF86XK_LAUNCH0", "DOM_VK_XF86XK_LAUNCH1", "DOM_VK_XF86XK_LAUNCH2", "DOM_VK_XF86XK_LAUNCH3", "DOM_VK_XF86XK_LAUNCH4", "DOM_VK_XF86XK_LAUNCH5", "DOM_VK_XF86XK_LAUNCH6", "DOM_VK_XF86XK_LAUNCH7", "DOM_VK_XF86XK_LAUNCH8", "DOM_VK_XF86XK_LAUNCH9", "DOM_VK_XF86XK_LAUNCH_A", "DOM_VK_XF86XK_LAUNCH_B", "DOM_VK_XF86XK_LAUNCH_C", "DOM_VK_XF86XK_LAUNCH_D", "DOM_VK_XF86XK_LAUNCH_E", "DOM_VK_XF86XK_LAUNCH_F", "DOM_VK_XF86XK_LIGHT_BULB", "DOM_VK_XF86XK_LOG_OFF", "DOM_VK_XF86XK_MAIL", "DOM_VK_XF86XK_MAIL_FORWARD", "DOM_VK_XF86XK_MARKET", "DOM_VK_XF86XK_MEETING", "DOM_VK_XF86XK_MEMO", "DOM_VK_XF86XK_MENU_KB", "DOM_VK_XF86XK_MENU_PB", "DOM_VK_XF86XK_MESSENGER", "DOM_VK_XF86XK_MON_BRIGHTNESS_DOWN", "DOM_VK_XF86XK_MON_BRIGHTNESS_UP", "DOM_VK_XF86XK_MUSIC", "DOM_VK_XF86XK_MY_COMPUTER", "DOM_VK_XF86XK_MY_SITES", "DOM_VK_XF86XK_NEW", "DOM_VK_XF86XK_NEWS", "DOM_VK_XF86XK_OFFICE_HOME", "DOM_VK_XF86XK_OPEN", "DOM_VK_XF86XK_OPEN_URL", "DOM_VK_XF86XK_OPTION", "DOM_VK_XF86XK_PASTE", "DOM_VK_XF86XK_PHONE", "DOM_VK_XF86XK_PICTURES", "DOM_VK_XF86XK_POWER_DOWN", "DOM_VK_XF86XK_POWER_OFF", "DOM_VK_XF86XK_RED", "DOM_VK_XF86XK_REFRESH", "DOM_VK_XF86XK_RELOAD", "DOM_VK_XF86XK_REPLY", "DOM_VK_XF86XK_ROCKER_DOWN", "DOM_VK_XF86XK_ROCKER_ENTER", "DOM_VK_XF86XK_ROCKER_UP", "DOM_VK_XF86XK_ROTATE_WINDOWS", "DOM_VK_XF86XK_ROTATION_KB", "DOM_VK_XF86XK_ROTATION_PB", "DOM_VK_XF86XK_SAVE", "DOM_VK_XF86XK_SCREEN_SAVER", "DOM_VK_XF86XK_SCROLL_CLICK", "DOM_VK_XF86XK_SCROLL_DOWN", "DOM_VK_XF86XK_SCROLL_UP", "DOM_VK_XF86XK_SEARCH", "DOM_VK_XF86XK_SEND", "DOM_VK_XF86XK_SHOP", "DOM_VK_XF86XK_SPELL", "DOM_VK_XF86XK_SPLIT_SCREEN", "DOM_VK_XF86XK_STANDBY", "DOM_VK_XF86XK_START", "DOM_VK_XF86XK_STOP", "DOM_VK_XF86XK_SUBTITLE", "DOM_VK_XF86XK_SUPPORT", "DOM_VK_XF86XK_SUSPEND", "DOM_VK_XF86XK_TASK_PANE", "DOM_VK_XF86XK_TERMINAL", "DOM_VK_XF86XK_TIME", "DOM_VK_XF86XK_TOOLS", "DOM_VK_XF86XK_TOP_MENU", "DOM_VK_XF86XK_TO_DO_LIST", "DOM_VK_XF86XK_TRAVEL", "DOM_VK_XF86XK_USER1KB", "DOM_VK_XF86XK_USER2KB", "DOM_VK_XF86XK_USER_PB", "DOM_VK_XF86XK_UWB", "DOM_VK_XF86XK_VENDOR_HOME", "DOM_VK_XF86XK_VIDEO", "DOM_VK_XF86XK_VIEW", "DOM_VK_XF86XK_WAKE_UP", "DOM_VK_XF86XK_WEB_CAM", "DOM_VK_XF86XK_WHEEL_BUTTON", "DOM_VK_XF86XK_WLAN", "DOM_VK_XF86XK_WORD", "DOM_VK_XF86XK_WWW", "DOM_VK_XF86XK_XFER", "DOM_VK_XF86XK_YELLOW", "DOM_VK_XF86XK_ZOOM_IN", "DOM_VK_XF86XK_ZOOM_OUT", "DOM_VK_Y", "DOM_VK_Z", "DOM_VK_ZOOM", "DONE", "DONT_CARE", "DOWNLOADING", "DRAGDROP", "DST_ALPHA", "DST_COLOR", "DYNAMIC_DRAW", "DataChannel", "DataTransfer", "DataTransferItem", "DataTransferItemList", "DataView", "Date", "DateTimeFormat", "DelayNode", "DesktopNotification", "DesktopNotificationCenter", "DeviceLightEvent", "DeviceMotionEvent", "DeviceOrientationEvent", "DeviceProximityEvent", "DeviceStorage", "DeviceStorageChangeEvent", "Document", "DocumentFragment", "DocumentType", "DragEvent", "DynamicsCompressorNode", "E", "ELEMENT_ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER_BINDING", "ELEMENT_NODE", "EMPTY", "ENCODING_ERR", "ENDED", "END_TO_END", "END_TO_START", "ENTITY_NODE", "ENTITY_REFERENCE_NODE", "EPSILON", "EQUAL", "EQUALPOWER", "ERROR", "EXPONENTIAL_DISTANCE", "Element", "ElementQuery", "Entity", "EntityReference", "Error", "ErrorEvent", "EvalError", "Event", "EventException", "EventSource", "EventTarget", "External", "FASTEST", "FIDOSDK", "FILTER_ACCEPT", "FILTER_INTERRUPT", "FILTER_REJECT", "FILTER_SKIP", "FINISHED_STATE", "FIRST_ORDERED_NODE_TYPE", "FLOAT", "FLOAT_MAT2", "FLOAT_MAT3", "FLOAT_MAT4", "FLOAT_VEC2", "FLOAT_VEC3", "FLOAT_VEC4", "FOCUS", "FONT_FACE_RULE", "FONT_FEATURE_VALUES_RULE", "FRAGMENT_SHADER", "FRAGMENT_SHADER_DERIVATIVE_HINT_OES", "FRAMEBUFFER", "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME", "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE", "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL", "FRAMEBUFFER_BINDING", "FRAMEBUFFER_COMPLETE", "FRAMEBUFFER_INCOMPLETE_ATTACHMENT", "FRAMEBUFFER_INCOMPLETE_DIMENSIONS", "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", "FRAMEBUFFER_UNSUPPORTED", "FRONT", "FRONT_AND_BACK", "FRONT_FACE", "FUNC_ADD", "FUNC_REVERSE_SUBTRACT", "FUNC_SUBTRACT", "Feed", "FeedEntry", "File", "FileError", "FileList", "FileReader", "FindInPage", "Float32Array", "Float64Array", "FocusEvent", "FontFace", "FormData", "Function", "GENERATE_MIPMAP_HINT", "GEQUAL", "GREATER", "GREEN_BITS", "GainNode", "Gamepad", "GamepadButton", "GamepadEvent", "GestureEvent", "HAVE_CURRENT_DATA", "HAVE_ENOUGH_DATA", "HAVE_FUTURE_DATA", "HAVE_METADATA", "HAVE_NOTHING", "HEADERS_RECEIVED", "HIDDEN", "HIERARCHY_REQUEST_ERR", "HIGHPASS", "HIGHSHELF", "HIGH_FLOAT", "HIGH_INT", "HORIZONTAL", "HORIZONTAL_AXIS", "HRTF", "HTMLAllCollection", "HTMLAnchorElement", "HTMLAppletElement", "HTMLAreaElement", "HTMLAudioElement", "HTMLBRElement", "HTMLBaseElement", "HTMLBaseFontElement", "HTMLBlockquoteElement", "HTMLBodyElement", "HTMLButtonElement", "HTMLCanvasElement", "HTMLCollection", "HTMLCommandElement", "HTMLContentElement", "HTMLDListElement", "HTMLDataElement", "HTMLDataListElement", "HTMLDetailsElement", "HTMLDialogElement", "HTMLDirectoryElement", "HTMLDivElement", "HTMLDocument", "HTMLElement", "HTMLEmbedElement", "HTMLFieldSetElement", "HTMLFontElement", "HTMLFormControlsCollection", "HTMLFormElement", "HTMLFrameElement", "HTMLFrameSetElement", "HTMLHRElement", "HTMLHeadElement", "HTMLHeadingElement", "HTMLHtmlElement", "HTMLIFrameElement", "HTMLImageElement", "HTMLInputElement", "HTMLIsIndexElement", "HTMLKeygenElement", "HTMLLIElement", "HTMLLabelElement", "HTMLLegendElement", "HTMLLinkElement", "HTMLMapElement", "HTMLMarqueeElement", "HTMLMediaElement", "HTMLMenuElement", "HTMLMenuItemElement", "HTMLMetaElement", "HTMLMeterElement", "HTMLModElement", "HTMLOListElement", "HTMLObjectElement", "HTMLOptGroupElement", "HTMLOptionElement", "HTMLOptionsCollection", "HTMLOutputElement", "HTMLParagraphElement", "HTMLParamElement", "HTMLPictureElement", "HTMLPreElement", "HTMLProgressElement", "HTMLPropertiesCollection", "HTMLQuoteElement", "HTMLScriptElement", "HTMLSelectElement", "HTMLShadowElement", "HTMLSourceElement", "HTMLSpanElement", "HTMLStyleElement", "HTMLTableCaptionElement", "HTMLTableCellElement", "HTMLTableColElement", "HTMLTableElement", "HTMLTableRowElement", "HTMLTableSectionElement", "HTMLTemplateElement", "HTMLTextAreaElement", "HTMLTimeElement", "HTMLTitleElement", "HTMLTrackElement", "HTMLUListElement", "HTMLUnknownElement", "HTMLVideoElement", "HashChangeEvent", "Headers", "History", "ICE_CHECKING", "ICE_CLOSED", "ICE_COMPLETED", "ICE_CONNECTED", "ICE_FAILED", "ICE_GATHERING", "ICE_WAITING", "IDBCursor", "IDBCursorWithValue", "IDBDatabase", "IDBDatabaseException", "IDBFactory", "IDBFileHandle", "IDBFileRequest", "IDBIndex", "IDBKeyRange", "IDBMutableFile", "IDBObjectStore", "IDBOpenDBRequest", "IDBRequest", "IDBTransaction", "IDBVersionChangeEvent", "IDLE", "IMPLEMENTATION_COLOR_READ_FORMAT", "IMPLEMENTATION_COLOR_READ_TYPE", "IMPORT_RULE", "INCR", "INCR_WRAP", "INDEX_SIZE_ERR", "INT", "INT_VEC2", "INT_VEC3", "INT_VEC4", "INUSE_ATTRIBUTE_ERR", "INVALID_ACCESS_ERR", "INVALID_CHARACTER_ERR", "INVALID_ENUM", "INVALID_EXPRESSION_ERR", "INVALID_FRAMEBUFFER_OPERATION", "INVALID_MODIFICATION_ERR", "INVALID_NODE_TYPE_ERR", "INVALID_OPERATION", "INVALID_STATE_ERR", "INVALID_VALUE", "INVERSE_DISTANCE", "INVERT", "IceCandidate", "Image", "ImageBitmap", "ImageData", "Infinity", "InputEvent", "InputMethodContext", "InstallTrigger", "Int16Array", "Int32Array", "Int8Array", "Intent", "InternalError", "Intl", "IsSearchProviderInstalled", "Iterator", "JSON", "KEEP", "KEYDOWN", "KEYFRAMES_RULE", "KEYFRAME_RULE", "KEYPRESS", "KEYUP", "KeyEvent", "KeyboardEvent", "LENGTHADJUST_SPACING", "LENGTHADJUST_SPACINGANDGLYPHS", "LENGTHADJUST_UNKNOWN", "LEQUAL", "LESS", "LINEAR", "LINEAR_DISTANCE", "LINEAR_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST", "LINES", "LINE_LOOP", "LINE_STRIP", "LINE_WIDTH", "LINK_STATUS", "LIVE", "LN10", "LN2", "LOADED", "LOADING", "LOG10E", "LOG2E", "LOWPASS", "LOWSHELF", "LOW_FLOAT", "LOW_INT", "LSException", "LSParserFilter", "LUMINANCE", "LUMINANCE_ALPHA", "LocalMediaStream", "Location", "MAX_COMBINED_TEXTURE_IMAGE_UNITS", "MAX_CUBE_MAP_TEXTURE_SIZE", "MAX_FRAGMENT_UNIFORM_VECTORS", "MAX_RENDERBUFFER_SIZE", "MAX_SAFE_INTEGER", "MAX_TEXTURE_IMAGE_UNITS", "MAX_TEXTURE_MAX_ANISOTROPY_EXT", "MAX_TEXTURE_SIZE", "MAX_VALUE", "MAX_VARYING_VECTORS", "MAX_VERTEX_ATTRIBS", "MAX_VERTEX_TEXTURE_IMAGE_UNITS", "MAX_VERTEX_UNIFORM_VECTORS", "MAX_VIEWPORT_DIMS", "MEDIA_ERR_ABORTED", "MEDIA_ERR_DECODE", "MEDIA_ERR_ENCRYPTED", "MEDIA_ERR_NETWORK", "MEDIA_ERR_SRC_NOT_SUPPORTED", "MEDIA_KEYERR_CLIENT", "MEDIA_KEYERR_DOMAIN", "MEDIA_KEYERR_HARDWARECHANGE", "MEDIA_KEYERR_OUTPUT", "MEDIA_KEYERR_SERVICE", "MEDIA_KEYERR_UNKNOWN", "MEDIA_RULE", "MEDIUM_FLOAT", "MEDIUM_INT", "META_MASK", "MIN_SAFE_INTEGER", "MIN_VALUE", "MIRRORED_REPEAT", "MODE_ASYNCHRONOUS", "MODE_SYNCHRONOUS", "MODIFICATION", "MOUSEDOWN", "MOUSEDRAG", "MOUSEMOVE", "MOUSEOUT", "MOUSEOVER", "MOUSEUP", "MOZ_KEYFRAMES_RULE", "MOZ_KEYFRAME_RULE", "MOZ_SOURCE_CURSOR", "MOZ_SOURCE_ERASER", "MOZ_SOURCE_KEYBOARD", "MOZ_SOURCE_MOUSE", "MOZ_SOURCE_PEN", "MOZ_SOURCE_TOUCH", "MOZ_SOURCE_UNKNOWN", "MSGESTURE_FLAG_BEGIN", "MSGESTURE_FLAG_CANCEL", "MSGESTURE_FLAG_END", "MSGESTURE_FLAG_INERTIA", "MSGESTURE_FLAG_NONE", "MSPOINTER_TYPE_MOUSE", "MSPOINTER_TYPE_PEN", "MSPOINTER_TYPE_TOUCH", "MS_ASYNC_CALLBACK_STATUS_ASSIGN_DELEGATE", "MS_ASYNC_CALLBACK_STATUS_CANCEL", "MS_ASYNC_CALLBACK_STATUS_CHOOSEANY", "MS_ASYNC_CALLBACK_STATUS_ERROR", "MS_ASYNC_CALLBACK_STATUS_JOIN", "MS_ASYNC_OP_STATUS_CANCELED", "MS_ASYNC_OP_STATUS_ERROR", "MS_ASYNC_OP_STATUS_SUCCESS", "MS_MANIPULATION_STATE_ACTIVE", "MS_MANIPULATION_STATE_CANCELLED", "MS_MANIPULATION_STATE_COMMITTED", "MS_MANIPULATION_STATE_DRAGGING", "MS_MANIPULATION_STATE_INERTIA", "MS_MANIPULATION_STATE_PRESELECT", "MS_MANIPULATION_STATE_SELECTING", "MS_MANIPULATION_STATE_STOPPED", "MS_MEDIA_ERR_ENCRYPTED", "MS_MEDIA_KEYERR_CLIENT", "MS_MEDIA_KEYERR_DOMAIN", "MS_MEDIA_KEYERR_HARDWARECHANGE", "MS_MEDIA_KEYERR_OUTPUT", "MS_MEDIA_KEYERR_SERVICE", "MS_MEDIA_KEYERR_UNKNOWN", "Map", "Math", "MediaController", "MediaDevices", "MediaElementAudioSourceNode", "MediaEncryptedEvent", "MediaError", "MediaKeyError", "MediaKeyEvent", "MediaKeyMessageEvent", "MediaKeyNeededEvent", "MediaKeySession", "MediaKeyStatusMap", "MediaKeySystemAccess", "MediaKeys", "MediaList", "MediaQueryList", "MediaQueryListEvent", "MediaRecorder", "MediaSource", "MediaStream", "MediaStreamAudioDestinationNode", "MediaStreamAudioSourceNode", "MediaStreamEvent", "MediaStreamTrack", "MediaStreamTrackEvent", "MessageChannel", "MessageEvent", "MessagePort", "Methods", "MimeType", "MimeTypeArray", "MouseEvent", "MouseScrollEvent", "MozAnimation", "MozAnimationDelay", "MozAnimationDirection", "MozAnimationDuration", "MozAnimationFillMode", "MozAnimationIterationCount", "MozAnimationName", "MozAnimationPlayState", "MozAnimationTimingFunction", "MozAppearance", "MozBackfaceVisibility", "MozBinding", "MozBorderBottomColors", "MozBorderEnd", "MozBorderEndColor", "MozBorderEndStyle", "MozBorderEndWidth", "MozBorderImage", "MozBorderLeftColors", "MozBorderRightColors", "MozBorderStart", "MozBorderStartColor", "MozBorderStartStyle", "MozBorderStartWidth", "MozBorderTopColors", "MozBoxAlign", "MozBoxDirection", "MozBoxFlex", "MozBoxOrdinalGroup", "MozBoxOrient", "MozBoxPack", "MozBoxSizing", "MozCSSKeyframeRule", "MozCSSKeyframesRule", "MozColumnCount", "MozColumnFill", "MozColumnGap", "MozColumnRule", "MozColumnRuleColor", "MozColumnRuleStyle", "MozColumnRuleWidth", "MozColumnWidth", "MozColumns", "MozContactChangeEvent", "MozFloatEdge", "MozFontFeatureSettings", "MozFontLanguageOverride", "MozForceBrokenImageIcon", "MozHyphens", "MozImageRegion", "MozMarginEnd", "MozMarginStart", "MozMmsEvent", "MozMmsMessage", "MozMobileMessageThread", "MozOSXFontSmoothing", "MozOrient", "MozOutlineRadius", "MozOutlineRadiusBottomleft", "MozOutlineRadiusBottomright", "MozOutlineRadiusTopleft", "MozOutlineRadiusTopright", "MozPaddingEnd", "MozPaddingStart", "MozPerspective", "MozPerspectiveOrigin", "MozPowerManager", "MozSettingsEvent", "MozSmsEvent", "MozSmsMessage", "MozStackSizing", "MozTabSize", "MozTextAlignLast", "MozTextDecorationColor", "MozTextDecorationLine", "MozTextDecorationStyle", "MozTextSizeAdjust", "MozTransform", "MozTransformOrigin", "MozTransformStyle", "MozTransition", "MozTransitionDelay", "MozTransitionDuration", "MozTransitionProperty", "MozTransitionTimingFunction", "MozUserFocus", "MozUserInput", "MozUserModify", "MozUserSelect", "MozWindowDragging", "MozWindowShadow", "MutationEvent", "MutationObserver", "MutationRecord", "NAMESPACE_ERR", "NAMESPACE_RULE", "NEAREST", "NEAREST_MIPMAP_LINEAR", "NEAREST_MIPMAP_NEAREST", "NEGATIVE_INFINITY", "NETWORK_EMPTY", "NETWORK_ERR", "NETWORK_IDLE", "NETWORK_LOADED", "NETWORK_LOADING", "NETWORK_NO_SOURCE", "NEVER", "NEW", "NEXT", "NEXT_NO_DUPLICATE", "NICEST", "NODE_AFTER", "NODE_BEFORE", "NODE_BEFORE_AND_AFTER", "NODE_INSIDE", "NONE", "NON_TRANSIENT_ERR", "NOTATION_NODE", "NOTCH", "NOTEQUAL", "NOT_ALLOWED_ERR", "NOT_FOUND_ERR", "NOT_READABLE_ERR", "NOT_SUPPORTED_ERR", "NO_DATA_ALLOWED_ERR", "NO_ERR", "NO_ERROR", "NO_MODIFICATION_ALLOWED_ERR", "NUMBER_TYPE", "NUM_COMPRESSED_TEXTURE_FORMATS", "NaN", "NamedNodeMap", "Navigator", "NearbyLinks", "NetworkInformation", "Node", "NodeFilter", "NodeIterator", "NodeList", "Notation", "Notification", "NotifyPaintEvent", "Number", "NumberFormat", "OBSOLETE", "ONE", "ONE_MINUS_CONSTANT_ALPHA", "ONE_MINUS_CONSTANT_COLOR", "ONE_MINUS_DST_ALPHA", "ONE_MINUS_DST_COLOR", "ONE_MINUS_SRC_ALPHA", "ONE_MINUS_SRC_COLOR", "OPEN", "OPENED", "OPENING", "ORDERED_NODE_ITERATOR_TYPE", "ORDERED_NODE_SNAPSHOT_TYPE", "OUT_OF_MEMORY", "Object", "OfflineAudioCompletionEvent", "OfflineAudioContext", "OfflineResourceList", "Option", "OscillatorNode", "OverflowEvent", "PACK_ALIGNMENT", "PAGE_RULE", "PARSE_ERR", "PATHSEG_ARC_ABS", "PATHSEG_ARC_REL", "PATHSEG_CLOSEPATH", "PATHSEG_CURVETO_CUBIC_ABS", "PATHSEG_CURVETO_CUBIC_REL", "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS", "PATHSEG_CURVETO_CUBIC_SMOOTH_REL", "PATHSEG_CURVETO_QUADRATIC_ABS", "PATHSEG_CURVETO_QUADRATIC_REL", "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS", "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL", "PATHSEG_LINETO_ABS", "PATHSEG_LINETO_HORIZONTAL_ABS", "PATHSEG_LINETO_HORIZONTAL_REL", "PATHSEG_LINETO_REL", "PATHSEG_LINETO_VERTICAL_ABS", "PATHSEG_LINETO_VERTICAL_REL", "PATHSEG_MOVETO_ABS", "PATHSEG_MOVETO_REL", "PATHSEG_UNKNOWN", "PATH_EXISTS_ERR", "PEAKING", "PERMISSION_DENIED", "PERSISTENT", "PI", "PLAYING_STATE", "POINTS", "POLYGON_OFFSET_FACTOR", "POLYGON_OFFSET_FILL", "POLYGON_OFFSET_UNITS", "POSITION_UNAVAILABLE", "POSITIVE_INFINITY", "PREV", "PREV_NO_DUPLICATE", "PROCESSING_INSTRUCTION_NODE", "PageChangeEvent", "PageTransitionEvent", "PaintRequest", "PaintRequestList", "PannerNode", "Path2D", "Performance", "PerformanceEntry", "PerformanceMark", "PerformanceMeasure", "PerformanceNavigation", "PerformanceResourceTiming", "PerformanceTiming", "PeriodicWave", "Plugin", "PluginArray", "PopStateEvent", "PopupBlockedEvent", "ProcessingInstruction", "ProgressEvent", "Promise", "PropertyNodeList", "Proxy", "PushManager", "PushSubscription", "Q", "QUOTA_ERR", "QUOTA_EXCEEDED_ERR", "QueryInterface", "READ_ONLY", "READ_ONLY_ERR", "READ_WRITE", "RED_BITS", "REMOVAL", "RENDERBUFFER", "RENDERBUFFER_ALPHA_SIZE", "RENDERBUFFER_BINDING", "RENDERBUFFER_BLUE_SIZE", "RENDERBUFFER_DEPTH_SIZE", "RENDERBUFFER_GREEN_SIZE", "RENDERBUFFER_HEIGHT", "RENDERBUFFER_INTERNAL_FORMAT", "RENDERBUFFER_RED_SIZE", "RENDERBUFFER_STENCIL_SIZE", "RENDERBUFFER_WIDTH", "RENDERER", "RENDERING_INTENT_ABSOLUTE_COLORIMETRIC", "RENDERING_INTENT_AUTO", "RENDERING_INTENT_PERCEPTUAL", "RENDERING_INTENT_RELATIVE_COLORIMETRIC", "RENDERING_INTENT_SATURATION", "RENDERING_INTENT_UNKNOWN", "REPEAT", "REPLACE", "RGB", "RGB565", "RGB5_A1", "RGBA", "RGBA4", "RGBColor", "ROTATION_CLOCKWISE", "ROTATION_COUNTERCLOCKWISE", "RTCDataChannelEvent", "RTCIceCandidate", "RTCPeerConnectionIceEvent", "RTCRtpReceiver", "RTCRtpSender", "RTCSessionDescription", "RTCStatsReport", "RadioNodeList", "Range", "RangeError", "RangeException", "RecordErrorEvent", "Rect", "ReferenceError", "RegExp", "Request", "Response", "SAMPLER_2D", "SAMPLER_CUBE", "SAMPLES", "SAMPLE_ALPHA_TO_COVERAGE", "SAMPLE_BUFFERS", "SAMPLE_COVERAGE", "SAMPLE_COVERAGE_INVERT", "SAMPLE_COVERAGE_VALUE", "SAWTOOTH", "SCHEDULED_STATE", "SCISSOR_BOX", "SCISSOR_TEST", "SCROLL_PAGE_DOWN", "SCROLL_PAGE_UP", "SDP_ANSWER", "SDP_OFFER", "SDP_PRANSWER", "SECURITY_ERR", "SELECT", "SERIALIZE_ERR", "SEVERITY_ERROR", "SEVERITY_FATAL_ERROR", "SEVERITY_WARNING", "SHADER_COMPILER", "SHADER_TYPE", "SHADING_LANGUAGE_VERSION", "SHIFT_MASK", "SHORT", "SHOWING", "SHOW_ALL", "SHOW_ATTRIBUTE", "SHOW_CDATA_SECTION", "SHOW_COMMENT", "SHOW_DOCUMENT", "SHOW_DOCUMENT_FRAGMENT", "SHOW_DOCUMENT_TYPE", "SHOW_ELEMENT", "SHOW_ENTITY", "SHOW_ENTITY_REFERENCE", "SHOW_NOTATION", "SHOW_PROCESSING_INSTRUCTION", "SHOW_TEXT", "SINE", "SOUNDFIELD", "SQLException", "SQRT1_2", "SQRT2", "SQUARE", "SRC_ALPHA", "SRC_ALPHA_SATURATE", "SRC_COLOR", "START_TO_END", "START_TO_START", "STATIC_DRAW", "STENCIL_ATTACHMENT", "STENCIL_BACK_FAIL", "STENCIL_BACK_FUNC", "STENCIL_BACK_PASS_DEPTH_FAIL", "STENCIL_BACK_PASS_DEPTH_PASS", "STENCIL_BACK_REF", "STENCIL_BACK_VALUE_MASK", "STENCIL_BACK_WRITEMASK", "STENCIL_BITS", "STENCIL_BUFFER_BIT", "STENCIL_CLEAR_VALUE", "STENCIL_FAIL", "STENCIL_FUNC", "STENCIL_INDEX", "STENCIL_INDEX8", "STENCIL_PASS_DEPTH_FAIL", "STENCIL_PASS_DEPTH_PASS", "STENCIL_REF", "STENCIL_TEST", "STENCIL_VALUE_MASK", "STENCIL_WRITEMASK", "STREAM_DRAW", "STRING_TYPE", "STYLE_RULE", "SUBPIXEL_BITS", "SUPPORTS_RULE", "SVGAElement", "SVGAltGlyphDefElement", "SVGAltGlyphElement", "SVGAltGlyphItemElement", "SVGAngle", "SVGAnimateColorElement", "SVGAnimateElement", "SVGAnimateMotionElement", "SVGAnimateTransformElement", "SVGAnimatedAngle", "SVGAnimatedBoolean", "SVGAnimatedEnumeration", "SVGAnimatedInteger", "SVGAnimatedLength", "SVGAnimatedLengthList", "SVGAnimatedNumber", "SVGAnimatedNumberList", "SVGAnimatedPreserveAspectRatio", "SVGAnimatedRect", "SVGAnimatedString", "SVGAnimatedTransformList", "SVGAnimationElement", "SVGCircleElement", "SVGClipPathElement", "SVGColor", "SVGComponentTransferFunctionElement", "SVGCursorElement", "SVGDefsElement", "SVGDescElement", "SVGDiscardElement", "SVGDocument", "SVGElement", "SVGElementInstance", "SVGElementInstanceList", "SVGEllipseElement", "SVGException", "SVGFEBlendElement", "SVGFEColorMatrixElement", "SVGFEComponentTransferElement", "SVGFECompositeElement", "SVGFEConvolveMatrixElement", "SVGFEDiffuseLightingElement", "SVGFEDisplacementMapElement", "SVGFEDistantLightElement", "SVGFEDropShadowElement", "SVGFEFloodElement", "SVGFEFuncAElement", "SVGFEFuncBElement", "SVGFEFuncGElement", "SVGFEFuncRElement", "SVGFEGaussianBlurElement", "SVGFEImageElement", "SVGFEMergeElement", "SVGFEMergeNodeElement", "SVGFEMorphologyElement", "SVGFEOffsetElement", "SVGFEPointLightElement", "SVGFESpecularLightingElement", "SVGFESpotLightElement", "SVGFETileElement", "SVGFETurbulenceElement", "SVGFilterElement", "SVGFontElement", "SVGFontFaceElement", "SVGFontFaceFormatElement", "SVGFontFaceNameElement", "SVGFontFaceSrcElement", "SVGFontFaceUriElement", "SVGForeignObjectElement", "SVGGElement", "SVGGeometryElement", "SVGGlyphElement", "SVGGlyphRefElement", "SVGGradientElement", "SVGGraphicsElement", "SVGHKernElement", "SVGImageElement", "SVGLength", "SVGLengthList", "SVGLineElement", "SVGLinearGradientElement", "SVGMPathElement", "SVGMarkerElement", "SVGMaskElement", "SVGMatrix", "SVGMetadataElement", "SVGMissingGlyphElement", "SVGNumber", "SVGNumberList", "SVGPaint", "SVGPathElement", "SVGPathSeg", "SVGPathSegArcAbs", "SVGPathSegArcRel", "SVGPathSegClosePath", "SVGPathSegCurvetoCubicAbs", "SVGPathSegCurvetoCubicRel", "SVGPathSegCurvetoCubicSmoothAbs", "SVGPathSegCurvetoCubicSmoothRel", "SVGPathSegCurvetoQuadraticAbs", "SVGPathSegCurvetoQuadraticRel", "SVGPathSegCurvetoQuadraticSmoothAbs", "SVGPathSegCurvetoQuadraticSmoothRel", "SVGPathSegLinetoAbs", "SVGPathSegLinetoHorizontalAbs", "SVGPathSegLinetoHorizontalRel", "SVGPathSegLinetoRel", "SVGPathSegLinetoVerticalAbs", "SVGPathSegLinetoVerticalRel", "SVGPathSegList", "SVGPathSegMovetoAbs", "SVGPathSegMovetoRel", "SVGPatternElement", "SVGPoint", "SVGPointList", "SVGPolygonElement", "SVGPolylineElement", "SVGPreserveAspectRatio", "SVGRadialGradientElement", "SVGRect", "SVGRectElement", "SVGRenderingIntent", "SVGSVGElement", "SVGScriptElement", "SVGSetElement", "SVGStopElement", "SVGStringList", "SVGStyleElement", "SVGSwitchElement", "SVGSymbolElement", "SVGTRefElement", "SVGTSpanElement", "SVGTextContentElement", "SVGTextElement", "SVGTextPathElement", "SVGTextPositioningElement", "SVGTitleElement", "SVGTransform", "SVGTransformList", "SVGUnitTypes", "SVGUseElement", "SVGVKernElement", "SVGViewElement", "SVGViewSpec", "SVGZoomAndPan", "SVGZoomEvent", "SVG_ANGLETYPE_DEG", "SVG_ANGLETYPE_GRAD", "SVG_ANGLETYPE_RAD", "SVG_ANGLETYPE_UNKNOWN", "SVG_ANGLETYPE_UNSPECIFIED", "SVG_CHANNEL_A", "SVG_CHANNEL_B", "SVG_CHANNEL_G", "SVG_CHANNEL_R", "SVG_CHANNEL_UNKNOWN", "SVG_COLORTYPE_CURRENTCOLOR", "SVG_COLORTYPE_RGBCOLOR", "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR", "SVG_COLORTYPE_UNKNOWN", "SVG_EDGEMODE_DUPLICATE", "SVG_EDGEMODE_NONE", "SVG_EDGEMODE_UNKNOWN", "SVG_EDGEMODE_WRAP", "SVG_FEBLEND_MODE_COLOR", "SVG_FEBLEND_MODE_COLOR_BURN", "SVG_FEBLEND_MODE_COLOR_DODGE", "SVG_FEBLEND_MODE_DARKEN", "SVG_FEBLEND_MODE_DIFFERENCE", "SVG_FEBLEND_MODE_EXCLUSION", "SVG_FEBLEND_MODE_HARD_LIGHT", "SVG_FEBLEND_MODE_HUE", "SVG_FEBLEND_MODE_LIGHTEN", "SVG_FEBLEND_MODE_LUMINOSITY", "SVG_FEBLEND_MODE_MULTIPLY", "SVG_FEBLEND_MODE_NORMAL", "SVG_FEBLEND_MODE_OVERLAY", "SVG_FEBLEND_MODE_SATURATION", "SVG_FEBLEND_MODE_SCREEN", "SVG_FEBLEND_MODE_SOFT_LIGHT", "SVG_FEBLEND_MODE_UNKNOWN", "SVG_FECOLORMATRIX_TYPE_HUEROTATE", "SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA", "SVG_FECOLORMATRIX_TYPE_MATRIX", "SVG_FECOLORMATRIX_TYPE_SATURATE", "SVG_FECOLORMATRIX_TYPE_UNKNOWN", "SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE", "SVG_FECOMPONENTTRANSFER_TYPE_GAMMA", "SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY", "SVG_FECOMPONENTTRANSFER_TYPE_LINEAR", "SVG_FECOMPONENTTRANSFER_TYPE_TABLE", "SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN", "SVG_FECOMPOSITE_OPERATOR_ARITHMETIC", "SVG_FECOMPOSITE_OPERATOR_ATOP", "SVG_FECOMPOSITE_OPERATOR_IN", "SVG_FECOMPOSITE_OPERATOR_OUT", "SVG_FECOMPOSITE_OPERATOR_OVER", "SVG_FECOMPOSITE_OPERATOR_UNKNOWN", "SVG_FECOMPOSITE_OPERATOR_XOR", "SVG_INVALID_VALUE_ERR", "SVG_LENGTHTYPE_CM", "SVG_LENGTHTYPE_EMS", "SVG_LENGTHTYPE_EXS", "SVG_LENGTHTYPE_IN", "SVG_LENGTHTYPE_MM", "SVG_LENGTHTYPE_NUMBER", "SVG_LENGTHTYPE_PC", "SVG_LENGTHTYPE_PERCENTAGE", "SVG_LENGTHTYPE_PT", "SVG_LENGTHTYPE_PX", "SVG_LENGTHTYPE_UNKNOWN", "SVG_MARKERUNITS_STROKEWIDTH", "SVG_MARKERUNITS_UNKNOWN", "SVG_MARKERUNITS_USERSPACEONUSE", "SVG_MARKER_ORIENT_ANGLE", "SVG_MARKER_ORIENT_AUTO", "SVG_MARKER_ORIENT_UNKNOWN", "SVG_MASKTYPE_ALPHA", "SVG_MASKTYPE_LUMINANCE", "SVG_MATRIX_NOT_INVERTABLE", "SVG_MEETORSLICE_MEET", "SVG_MEETORSLICE_SLICE", "SVG_MEETORSLICE_UNKNOWN", "SVG_MORPHOLOGY_OPERATOR_DILATE", "SVG_MORPHOLOGY_OPERATOR_ERODE", "SVG_MORPHOLOGY_OPERATOR_UNKNOWN", "SVG_PAINTTYPE_CURRENTCOLOR", "SVG_PAINTTYPE_NONE", "SVG_PAINTTYPE_RGBCOLOR", "SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR", "SVG_PAINTTYPE_UNKNOWN", "SVG_PAINTTYPE_URI", "SVG_PAINTTYPE_URI_CURRENTCOLOR", "SVG_PAINTTYPE_URI_NONE", "SVG_PAINTTYPE_URI_RGBCOLOR", "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR", "SVG_PRESERVEASPECTRATIO_NONE", "SVG_PRESERVEASPECTRATIO_UNKNOWN", "SVG_PRESERVEASPECTRATIO_XMAXYMAX", "SVG_PRESERVEASPECTRATIO_XMAXYMID", "SVG_PRESERVEASPECTRATIO_XMAXYMIN", "SVG_PRESERVEASPECTRATIO_XMIDYMAX", "SVG_PRESERVEASPECTRATIO_XMIDYMID", "SVG_PRESERVEASPECTRATIO_XMIDYMIN", "SVG_PRESERVEASPECTRATIO_XMINYMAX", "SVG_PRESERVEASPECTRATIO_XMINYMID", "SVG_PRESERVEASPECTRATIO_XMINYMIN", "SVG_SPREADMETHOD_PAD", "SVG_SPREADMETHOD_REFLECT", "SVG_SPREADMETHOD_REPEAT", "SVG_SPREADMETHOD_UNKNOWN", "SVG_STITCHTYPE_NOSTITCH", "SVG_STITCHTYPE_STITCH", "SVG_STITCHTYPE_UNKNOWN", "SVG_TRANSFORM_MATRIX", "SVG_TRANSFORM_ROTATE", "SVG_TRANSFORM_SCALE", "SVG_TRANSFORM_SKEWX", "SVG_TRANSFORM_SKEWY", "SVG_TRANSFORM_TRANSLATE", "SVG_TRANSFORM_UNKNOWN", "SVG_TURBULENCE_TYPE_FRACTALNOISE", "SVG_TURBULENCE_TYPE_TURBULENCE", "SVG_TURBULENCE_TYPE_UNKNOWN", "SVG_UNIT_TYPE_OBJECTBOUNDINGBOX", "SVG_UNIT_TYPE_UNKNOWN", "SVG_UNIT_TYPE_USERSPACEONUSE", "SVG_WRONG_TYPE_ERR", "SVG_ZOOMANDPAN_DISABLE", "SVG_ZOOMANDPAN_MAGNIFY", "SVG_ZOOMANDPAN_UNKNOWN", "SYNTAX_ERR", "SavedPages", "Screen", "ScreenOrientation", "Script", "ScriptProcessorNode", "ScrollAreaEvent", "SecurityPolicyViolationEvent", "Selection", "ServiceWorker", "ServiceWorkerContainer", "ServiceWorkerRegistration", "SessionDescription", "Set", "ShadowRoot", "SharedWorker", "SimpleGestureEvent", "SpeechSynthesisEvent", "SpeechSynthesisUtterance", "StopIteration", "Storage", "StorageEvent", "String", "StyleSheet", "StyleSheetList", "SubtleCrypto", "Symbol", "SyntaxError", "TEMPORARY", "TEXTPATH_METHODTYPE_ALIGN", "TEXTPATH_METHODTYPE_STRETCH", "TEXTPATH_METHODTYPE_UNKNOWN", "TEXTPATH_SPACINGTYPE_AUTO", "TEXTPATH_SPACINGTYPE_EXACT", "TEXTPATH_SPACINGTYPE_UNKNOWN", "TEXTURE", "TEXTURE0", "TEXTURE1", "TEXTURE10", "TEXTURE11", "TEXTURE12", "TEXTURE13", "TEXTURE14", "TEXTURE15", "TEXTURE16", "TEXTURE17", "TEXTURE18", "TEXTURE19", "TEXTURE2", "TEXTURE20", "TEXTURE21", "TEXTURE22", "TEXTURE23", "TEXTURE24", "TEXTURE25", "TEXTURE26", "TEXTURE27", "TEXTURE28", "TEXTURE29", "TEXTURE3", "TEXTURE30", "TEXTURE31", "TEXTURE4", "TEXTURE5", "TEXTURE6", "TEXTURE7", "TEXTURE8", "TEXTURE9", "TEXTURE_2D", "TEXTURE_BINDING_2D", "TEXTURE_BINDING_CUBE_MAP", "TEXTURE_CUBE_MAP", "TEXTURE_CUBE_MAP_NEGATIVE_X", "TEXTURE_CUBE_MAP_NEGATIVE_Y", "TEXTURE_CUBE_MAP_NEGATIVE_Z", "TEXTURE_CUBE_MAP_POSITIVE_X", "TEXTURE_CUBE_MAP_POSITIVE_Y", "TEXTURE_CUBE_MAP_POSITIVE_Z", "TEXTURE_MAG_FILTER", "TEXTURE_MAX_ANISOTROPY_EXT", "TEXTURE_MIN_FILTER", "TEXTURE_WRAP_S", "TEXTURE_WRAP_T", "TEXT_NODE", "TIMEOUT", "TIMEOUT_ERR", "TOO_LARGE_ERR", "TRANSACTION_INACTIVE_ERR", "TRIANGLE", "TRIANGLES", "TRIANGLE_FAN", "TRIANGLE_STRIP", "TYPE_BACK_FORWARD", "TYPE_ERR", "TYPE_MISMATCH_ERR", "TYPE_NAVIGATE", "TYPE_RELOAD", "TYPE_RESERVED", "Text", "TextDecoder", "TextEncoder", "TextEvent", "TextMetrics", "TextTrack", "TextTrackCue", "TextTrackCueList", "TextTrackList", "TimeEvent", "TimeRanges", "Touch", "TouchEvent", "TouchList", "TrackEvent", "TransitionEvent", "TreeWalker", "TypeError", "UIEvent", "UNCACHED", "UNKNOWN_ERR", "UNKNOWN_RULE", "UNMASKED_RENDERER_WEBGL", "UNMASKED_VENDOR_WEBGL", "UNORDERED_NODE_ITERATOR_TYPE", "UNORDERED_NODE_SNAPSHOT_TYPE", "UNPACK_ALIGNMENT", "UNPACK_COLORSPACE_CONVERSION_WEBGL", "UNPACK_FLIP_Y_WEBGL", "UNPACK_PREMULTIPLY_ALPHA_WEBGL", "UNSCHEDULED_STATE", "UNSENT", "UNSIGNED_BYTE", "UNSIGNED_INT", "UNSIGNED_SHORT", "UNSIGNED_SHORT_4_4_4_4", "UNSIGNED_SHORT_5_5_5_1", "UNSIGNED_SHORT_5_6_5", "UNSPECIFIED_EVENT_TYPE_ERR", "UPDATEREADY", "URIError", "URL", "URLSearchParams", "URLUnencoded", "URL_MISMATCH_ERR", "UTC", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray", "UserMessageHandler", "UserMessageHandlersNamespace", "UserProximityEvent", "VALIDATE_STATUS", "VALIDATION_ERR", "VARIABLES_RULE", "VENDOR", "VERSION", "VERSION_CHANGE", "VERSION_ERR", "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", "VERTEX_ATTRIB_ARRAY_ENABLED", "VERTEX_ATTRIB_ARRAY_NORMALIZED", "VERTEX_ATTRIB_ARRAY_POINTER", "VERTEX_ATTRIB_ARRAY_SIZE", "VERTEX_ATTRIB_ARRAY_STRIDE", "VERTEX_ATTRIB_ARRAY_TYPE", "VERTEX_SHADER", "VERTICAL", "VERTICAL_AXIS", "VER_ERR", "VIEWPORT", "VIEWPORT_RULE", "VTTCue", "VTTRegion", "ValidityState", "VideoStreamTrack", "WEBKIT_FILTER_RULE", "WEBKIT_KEYFRAMES_RULE", "WEBKIT_KEYFRAME_RULE", "WEBKIT_REGION_RULE", "WRONG_DOCUMENT_ERR", "WaveShaperNode", "WeakMap", "WeakSet", "WebGLActiveInfo", "WebGLBuffer", "WebGLContextEvent", "WebGLFramebuffer", "WebGLProgram", "WebGLRenderbuffer", "WebGLRenderingContext", "WebGLShader", "WebGLShaderPrecisionFormat", "WebGLTexture", "WebGLUniformLocation", "WebGLVertexArray", "WebKitAnimationEvent", "WebKitBlobBuilder", "WebKitCSSFilterRule", "WebKitCSSFilterValue", "WebKitCSSKeyframeRule", "WebKitCSSKeyframesRule", "WebKitCSSMatrix", "WebKitCSSRegionRule", "WebKitCSSTransformValue", "WebKitDataCue", "WebKitGamepad", "WebKitMediaKeyError", "WebKitMediaKeyMessageEvent", "WebKitMediaKeySession", "WebKitMediaKeys", "WebKitMediaSource", "WebKitMutationObserver", "WebKitNamespace", "WebKitPlaybackTargetAvailabilityEvent", "WebKitPoint", "WebKitShadowRoot", "WebKitSourceBuffer", "WebKitSourceBufferList", "WebKitTransitionEvent", "WebSocket", "WheelEvent", "Window", "Worker", "XMLDocument", "XMLHttpRequest", "XMLHttpRequestEventTarget", "XMLHttpRequestException", "XMLHttpRequestProgressEvent", "XMLHttpRequestUpload", "XMLSerializer", "XMLStylesheetProcessingInstruction", "XPathEvaluator", "XPathException", "XPathExpression", "XPathNSResolver", "XPathResult", "XSLTProcessor", "ZERO", "_XD0M_", "_YD0M_", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__opera", "__proto__", "_browserjsran", "a", "aLink", "abbr", "abort", "abs", "absolute", "acceleration", "accelerationIncludingGravity", "accelerator", "accept", "acceptCharset", "acceptNode", "accessKey", "accessKeyLabel", "accuracy", "acos", "acosh", "action", "actionURL", "active", "activeCues", "activeElement", "activeSourceBuffers", "activeSourceCount", "activeTexture", "add", "addBehavior", "addCandidate", "addColorStop", "addCue", "addElement", "addEventListener", "addFilter", "addFromString", "addFromUri", "addIceCandidate", "addImport", "addListener", "addNamed", "addPageRule", "addPath", "addPointer", "addRange", "addRegion", "addRule", "addSearchEngine", "addSourceBuffer", "addStream", "addTextTrack", "addTrack", "addWakeLockListener", "addedNodes", "additionalName", "additiveSymbols", "addons", "adoptNode", "adr", "advance", "alert", "algorithm", "align", "align-content", "align-items", "align-self", "alignContent", "alignItems", "alignSelf", "alignmentBaseline", "alinkColor", "all", "allowFullscreen", "allowedDirections", "alpha", "alt", "altGraphKey", "altHtml", "altKey", "altLeft", "altitude", "altitudeAccuracy", "amplitude", "ancestorOrigins", "anchor", "anchorNode", "anchorOffset", "anchors", "angle", "animVal", "animate", "animatedInstanceRoot", "animatedNormalizedPathSegList", "animatedPathSegList", "animatedPoints", "animation", "animation-delay", "animation-direction", "animation-duration", "animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state", "animation-timing-function", "animationDelay", "animationDirection", "animationDuration", "animationFillMode", "animationIterationCount", "animationName", "animationPlayState", "animationStartTime", "animationTimingFunction", "animationsPaused", "anniversary", "app", "appCodeName", "appMinorVersion", "appName", "appNotifications", "appVersion", "append", "appendBuffer", "appendChild", "appendData", "appendItem", "appendMedium", "appendNamed", "appendRule", "appendStream", "appendWindowEnd", "appendWindowStart", "applets", "applicationCache", "apply", "applyElement", "arc", "arcTo", "archive", "areas", "arguments", "arrayBuffer", "asin", "asinh", "assert", "assign", "async", "atEnd", "atan", "atan2", "atanh", "atob", "attachEvent", "attachShader", "attachments", "attack", "attrChange", "attrName", "attributeName", "attributeNamespace", "attributes", "audioTracks", "autoIncrement", "autobuffer", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "autoplay", "availHeight", "availLeft", "availTop", "availWidth", "availability", "available", "aversion", "axes", "axis", "azimuth", "b", "back", "backface-visibility", "backfaceVisibility", "background", "background-attachment", "background-blend-mode", "background-clip", "background-color", "background-image", "background-origin", "background-position", "background-repeat", "background-size", "backgroundAttachment", "backgroundBlendMode", "backgroundClip", "backgroundColor", "backgroundImage", "backgroundOrigin", "backgroundPosition", "backgroundPositionX", "backgroundPositionY", "backgroundRepeat", "backgroundSize", "badInput", "balance", "baseFrequencyX", "baseFrequencyY", "baseNode", "baseOffset", "baseURI", "baseVal", "baselineShift", "battery", "bday", "beginElement", "beginElementAt", "beginPath", "behavior", "behaviorCookie", "behaviorPart", "behaviorUrns", "beta", "bezierCurveTo", "bgColor", "bgProperties", "bias", "big", "binaryType", "bind", "bindAttribLocation", "bindBuffer", "bindFramebuffer", "bindRenderbuffer", "bindTexture", "blendColor", "blendEquation", "blendEquationSeparate", "blendFunc", "blendFuncSeparate", "blink", "blob", "blockDirection", "blue", "blur", "body", "bodyUsed", "bold", "bookmarks", "booleanValue", "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", "border-collapse", "border-color", "border-image", "border-image-outset", "border-image-repeat", "border-image-slice", "border-image-source", "border-image-width", "border-left", "border-left-color", "border-left-style", "border-left-width", "border-radius", "border-right", "border-right-color", "border-right-style", "border-right-width", "border-spacing", "border-style", "border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius", "border-top-style", "border-top-width", "border-width", "borderBottom", "borderBottomColor", "borderBottomLeftRadius", "borderBottomRightRadius", "borderBottomStyle", "borderBottomWidth", "borderCollapse", "borderColor", "borderColorDark", "borderColorLight", "borderImage", "borderImageOutset", "borderImageRepeat", "borderImageSlice", "borderImageSource", "borderImageWidth", "borderLeft", "borderLeftColor", "borderLeftStyle", "borderLeftWidth", "borderRadius", "borderRight", "borderRightColor", "borderRightStyle", "borderRightWidth", "borderSpacing", "borderStyle", "borderTop", "borderTopColor", "borderTopLeftRadius", "borderTopRightRadius", "borderTopStyle", "borderTopWidth", "borderWidth", "bottom", "bottomMargin", "bound", "boundElements", "boundingClientRect", "boundingHeight", "boundingLeft", "boundingTop", "boundingWidth", "bounds", "box-decoration-break", "box-shadow", "box-sizing", "boxDecorationBreak", "boxShadow", "boxSizing", "breakAfter", "breakBefore", "breakInside", "browserLanguage", "btoa", "bubbles", "buffer", "bufferData", "bufferDepth", "bufferSize", "bufferSubData", "buffered", "bufferedAmount", "buildID", "buildNumber", "button", "buttonID", "buttons", "byteLength", "byteOffset", "c", "call", "caller", "canBeFormatted", "canBeMounted", "canBeShared", "canHaveChildren", "canHaveHTML", "canPlayType", "cancel", "cancelAnimationFrame", "cancelBubble", "cancelScheduledValues", "cancelable", "candidate", "canvas", "caption", "caption-side", "captionSide", "captureEvents", "captureStackTrace", "caretPositionFromPoint", "caretRangeFromPoint", "cast", "catch", "category", "cbrt", "cd", "ceil", "cellIndex", "cellPadding", "cellSpacing", "cells", "ch", "chOff", "chain", "challenge", "changedTouches", "channel", "channelCount", "channelCountMode", "channelInterpretation", "char", "charAt", "charCode", "charCodeAt", "charIndex", "characterSet", "charging", "chargingTime", "charset", "checkEnclosure", "checkFramebufferStatus", "checkIntersection", "checkValidity", "checked", "childElementCount", "childNodes", "children", "chrome", "ciphertext", "cite", "classList", "className", "classid", "clear", "clearAttributes", "clearColor", "clearData", "clearDepth", "clearImmediate", "clearInterval", "clearMarks", "clearMeasures", "clearParameters", "clearRect", "clearResourceTimings", "clearShadow", "clearStencil", "clearTimeout", "clearWatch", "click", "clickCount", "clientHeight", "clientInformation", "clientLeft", "clientRect", "clientRects", "clientTop", "clientWidth", "clientX", "clientY", "clip", "clip-path", "clip-rule", "clipBottom", "clipLeft", "clipPath", "clipPathUnits", "clipRight", "clipRule", "clipTop", "clipboardData", "clone", "cloneContents", "cloneNode", "cloneRange", "close", "closePath", "closed", "closest", "clz", "clz32", "cmp", "code", "codeBase", "codePointAt", "codeType", "colSpan", "collapse", "collapseToEnd", "collapseToStart", "collapsed", "collect", "colno", "color", "color-interpolation", "color-interpolation-filters", "colorDepth", "colorInterpolation", "colorInterpolationFilters", "colorMask", "colorType", "cols", "columnCount", "columnFill", "columnGap", "columnNumber", "columnRule", "columnRuleColor", "columnRuleStyle", "columnRuleWidth", "columnSpan", "columnWidth", "columns", "command", "commitPreferences", "commonAncestorContainer", "compact", "compareBoundaryPoints", "compareDocumentPosition", "compareEndPoints", "compareNode", "comparePoint", "compatMode", "compatible", "compile", "compileShader", "complete", "componentFromPoint", "compositionEndOffset", "compositionStartOffset", "compressedTexImage2D", "compressedTexSubImage2D", "concat", "conditionText", "coneInnerAngle", "coneOuterAngle", "coneOuterGain", "confirm", "confirmComposition", "confirmSiteSpecificTrackingException", "confirmWebWideTrackingException", "connect", "connectEnd", "connectStart", "connected", "connection", "connectionSpeed", "console", "consolidate", "constrictionActive", "constructor", "contactID", "contains", "containsNode", "content", "contentDocument", "contentEditable", "contentOverflow", "contentScriptType", "contentStyleType", "contentType", "contentWindow", "context", "contextMenu", "contextmenu", "continue", "continuous", "control", "controller", "controls", "convertToSpecifiedUnits", "cookie", "cookieEnabled", "coords", "copyFromChannel", "copyTexImage2D", "copyTexSubImage2D", "copyToChannel", "copyWithin", "correspondingElement", "correspondingUseElement", "cos", "cosh", "count", "counter-increment", "counter-reset", "counterIncrement", "counterReset", "cpuClass", "cpuSleepAllowed", "create", "createAnalyser", "createAnswer", "createAttribute", "createAttributeNS", "createBiquadFilter", "createBuffer", "createBufferSource", "createCDATASection", "createCSSStyleSheet", "createCaption", "createChannelMerger", "createChannelSplitter", "createComment", "createContextualFragment", "createControlRange", "createConvolver", "createDTMFSender", "createDataChannel", "createDelay", "createDelayNode", "createDocument", "createDocumentFragment", "createDocumentType", "createDynamicsCompressor", "createElement", "createElementNS", "createEntityReference", "createEvent", "createEventObject", "createExpression", "createFramebuffer", "createFunction", "createGain", "createGainNode", "createHTMLDocument", "createImageBitmap", "createImageData", "createIndex", "createJavaScriptNode", "createLinearGradient", "createMediaElementSource", "createMediaKeys", "createMediaStreamDestination", "createMediaStreamSource", "createMutableFile", "createNSResolver", "createNodeIterator", "createNotification", "createObjectStore", "createObjectURL", "createOffer", "createOscillator", "createPanner", "createPattern", "createPeriodicWave", "createPopup", "createProcessingInstruction", "createProgram", "createRadialGradient", "createRange", "createRangeCollection", "createRenderbuffer", "createSVGAngle", "createSVGLength", "createSVGMatrix", "createSVGNumber", "createSVGPathSegArcAbs", "createSVGPathSegArcRel", "createSVGPathSegClosePath", "createSVGPathSegCurvetoCubicAbs", "createSVGPathSegCurvetoCubicRel", "createSVGPathSegCurvetoCubicSmoothAbs", "createSVGPathSegCurvetoCubicSmoothRel", "createSVGPathSegCurvetoQuadraticAbs", "createSVGPathSegCurvetoQuadraticRel", "createSVGPathSegCurvetoQuadraticSmoothAbs", "createSVGPathSegCurvetoQuadraticSmoothRel", "createSVGPathSegLinetoAbs", "createSVGPathSegLinetoHorizontalAbs", "createSVGPathSegLinetoHorizontalRel", "createSVGPathSegLinetoRel", "createSVGPathSegLinetoVerticalAbs", "createSVGPathSegLinetoVerticalRel", "createSVGPathSegMovetoAbs", "createSVGPathSegMovetoRel", "createSVGPoint", "createSVGRect", "createSVGTransform", "createSVGTransformFromMatrix", "createScriptProcessor", "createSession", "createShader", "createShadowRoot", "createStereoPanner", "createStyleSheet", "createTBody", "createTFoot", "createTHead", "createTextNode", "createTextRange", "createTexture", "createTouch", "createTouchList", "createTreeWalker", "createWaveShaper", "creationTime", "crossOrigin", "crypto", "csi", "cssFloat", "cssRules", "cssText", "cssValueType", "ctrlKey", "ctrlLeft", "cues", "cullFace", "currentNode", "currentPage", "currentScale", "currentScript", "currentSrc", "currentState", "currentStyle", "currentTarget", "currentTime", "currentTranslate", "currentView", "cursor", "curve", "customError", "cx", "cy", "d", "data", "dataFld", "dataFormatAs", "dataPageSize", "dataSrc", "dataTransfer", "database", "dataset", "dateTime", "db", "debug", "debuggerEnabled", "declare", "decode", "decodeAudioData", "decodeURI", "decodeURIComponent", "decrypt", "default", "defaultCharset", "defaultChecked", "defaultMuted", "defaultPlaybackRate", "defaultPrevented", "defaultSelected", "defaultStatus", "defaultURL", "defaultValue", "defaultView", "defaultstatus", "defer", "defineMagicFunction", "defineMagicVariable", "defineProperties", "defineProperty", "delayTime", "delete", "deleteBuffer", "deleteCaption", "deleteCell", "deleteContents", "deleteData", "deleteDatabase", "deleteFramebuffer", "deleteFromDocument", "deleteIndex", "deleteMedium", "deleteObjectStore", "deleteProgram", "deleteRenderbuffer", "deleteRow", "deleteRule", "deleteShader", "deleteTFoot", "deleteTHead", "deleteTexture", "deliverChangeRecords", "delivery", "deliveryInfo", "deliveryStatus", "deliveryTimestamp", "delta", "deltaMode", "deltaX", "deltaY", "deltaZ", "depthFunc", "depthMask", "depthRange", "deriveBits", "deriveKey", "description", "deselectAll", "designMode", "destination", "destinationURL", "detach", "detachEvent", "detachShader", "detail", "detune", "devicePixelRatio", "deviceXDPI", "deviceYDPI", "diffuseConstant", "digest", "dimensions", "dir", "dirName", "direction", "dirxml", "disable", "disableVertexAttribArray", "disabled", "dischargingTime", "disconnect", "dispatchEvent", "display", "distanceModel", "divisor", "djsapi", "djsproxy", "doImport", "doNotTrack", "doScroll", "doctype", "document", "documentElement", "documentMode", "documentURI", "dolphin", "dolphinGameCenter", "dolphininfo", "dolphinmeta", "domComplete", "domContentLoadedEventEnd", "domContentLoadedEventStart", "domInteractive", "domLoading", "domain", "domainLookupEnd", "domainLookupStart", "dominant-baseline", "dominantBaseline", "done", "dopplerFactor", "download", "dragDrop", "draggable", "drawArrays", "drawArraysInstancedANGLE", "drawCustomFocusRing", "drawElements", "drawElementsInstancedANGLE", "drawFocusIfNeeded", "drawImage", "drawImageFromRect", "drawSystemFocusRing", "drawingBufferHeight", "drawingBufferWidth", "dropEffect", "droppedVideoFrames", "dropzone", "dump", "duplicate", "duration", "dvname", "dvnum", "dx", "dy", "dynsrc", "e", "edgeMode", "effectAllowed", "elapsedTime", "elementFromPoint", "elements", "elevation", "ellipse", "email", "embeds", "empty", "empty-cells", "emptyCells", "enable", "enableBackground", "enableStyleSheetsForSet", "enableVertexAttribArray", "enabled", "enabledPlugin", "encode", "encodeURI", "encodeURIComponent", "encoding", "encrypt", "enctype", "end", "endContainer", "endElement", "endElementAt", "endOfStream", "endOffset", "endTime", "ended", "endsWith", "entities", "entries", "entryType", "enumerate", "enumerateEditable", "error", "errorCode", "escape", "eval", "evaluate", "event", "eventPhase", "every", "exception", "exec", "execCommand", "execCommandShowHelp", "execScript", "exitFullscreen", "exitPointerLock", "exp", "expand", "expandEntityReferences", "expando", "expansion", "expiryDate", "explicitOriginalTarget", "expm1", "exponent", "exponentialRampToValueAtTime", "exportKey", "extend", "extensions", "extentNode", "extentOffset", "external", "externalResourcesRequired", "extractContents", "extractable", "f", "face", "factoryReset", "fallback", "familyName", "farthestViewportElement", "fastSeek", "fatal", "fetch", "fetchStart", "fftSize", "fgColor", "fileCreatedDate", "fileHandle", "fileModifiedDate", "fileName", "fileSize", "fileUpdatedDate", "filename", "files", "fill", "fill-opacity", "fill-rule", "fillOpacity", "fillRect", "fillRule", "fillStyle", "fillText", "filter", "filterResX", "filterResY", "filterUnits", "filters", "find", "findIndex", "findRule", "findText", "finish", "fireEvent", "firstChild", "firstElementChild", "firstPage", "fixed", "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", "flexBasis", "flexDirection", "flexFlow", "flexGrow", "flexShrink", "flexWrap", "flipX", "flipY", "float", "flood-color", "flood-opacity", "floodColor", "floodOpacity", "floor", "flush", "focus", "focusNode", "focusOffset", "font", "font-family", "font-feature-settings", "font-kerning", "font-language-override", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-synthesis", "font-variant", "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", "font-variant-position", "font-weight", "fontFamily", "fontFeatureSettings", "fontKerning", "fontLanguageOverride", "fontSize", "fontSizeAdjust", "fontSmoothingEnabled", "fontStretch", "fontStyle", "fontSynthesis", "fontVariant", "fontVariantAlternates", "fontVariantCaps", "fontVariantEastAsian", "fontVariantLigatures", "fontVariantNumeric", "fontVariantPosition", "fontWeight", "fontcolor", "fonts", "fontsize", "for", "forEach", "forceRedraw", "form", "formAction", "formEnctype", "formMethod", "formNoValidate", "formTarget", "format", "forms", "forward", "fr", "frame", "frameBorder", "frameElement", "frameSpacing", "framebufferRenderbuffer", "framebufferTexture2D", "frames", "freeSpace", "freeze", "frequency", "frequencyBinCount", "from", "fromCharCode", "fromCodePoint", "fromElement", "frontFace", "fround", "fullScreen", "fullscreenElement", "fullscreenEnabled", "fx", "fy", "gain", "gamepad", "gamma", "genderIdentity", "generateKey", "generateMipmap", "generateRequest", "geolocation", "gestureObject", "get", "getActiveAttrib", "getActiveUniform", "getAdjacentText", "getAll", "getAllResponseHeaders", "getAsFile", "getAsString", "getAttachedShaders", "getAttribLocation", "getAttribute", "getAttributeNS", "getAttributeNode", "getAttributeNodeNS", "getAudioTracks", "getBBox", "getBattery", "getBlob", "getBookmark", "getBoundingClientRect", "getBufferParameter", "getByteFrequencyData", "getByteTimeDomainData", "getCSSCanvasContext", "getCTM", "getCandidateWindowClientRect", "getChannelData", "getCharNumAtPosition", "getClientRect", "getClientRects", "getCompositionAlternatives", "getComputedStyle", "getComputedTextLength", "getConfiguration", "getContext", "getContextAttributes", "getCounterValue", "getCueAsHTML", "getCueById", "getCurrentPosition", "getCurrentTime", "getData", "getDatabaseNames", "getDate", "getDay", "getDefaultComputedStyle", "getDestinationInsertionPoints", "getDistributedNodes", "getEditable", "getElementById", "getElementsByClassName", "getElementsByName", "getElementsByTagName", "getElementsByTagNameNS", "getEnclosureList", "getEndPositionOfChar", "getEntries", "getEntriesByName", "getEntriesByType", "getError", "getExtension", "getExtentOfChar", "getFeature", "getFile", "getFloat32", "getFloat64", "getFloatFrequencyData", "getFloatTimeDomainData", "getFloatValue", "getFramebufferAttachmentParameter", "getFrequencyResponse", "getFullYear", "getGamepads", "getHours", "getImageData", "getInt16", "getInt32", "getInt8", "getIntersectionList", "getItem", "getItems", "getKey", "getLineDash", "getLocalStreams", "getMarks", "getMatchedCSSRules", "getMeasures", "getMetadata", "getMilliseconds", "getMinutes", "getModifierState", "getMonth", "getNamedItem", "getNamedItemNS", "getNotifier", "getNumberOfChars", "getOverrideHistoryNavigationMode", "getOverrideStyle", "getOwnPropertyDescriptor", "getOwnPropertyNames", "getOwnPropertySymbols", "getParameter", "getPathSegAtLength", "getPointAtLength", "getPreference", "getPreferenceDefault", "getPresentationAttribute", "getPreventDefault", "getProgramInfoLog", "getProgramParameter", "getPropertyCSSValue", "getPropertyPriority", "getPropertyShorthand", "getPropertyValue", "getPrototypeOf", "getRGBColorValue", "getRandomValues", "getRangeAt", "getReceivers", "getRectValue", "getRegistration", "getRemoteStreams", "getRenderbufferParameter", "getResponseHeader", "getRoot", "getRotationOfChar", "getSVGDocument", "getScreenCTM", "getSeconds", "getSelection", "getSenders", "getShaderInfoLog", "getShaderParameter", "getShaderPrecisionFormat", "getShaderSource", "getSimpleDuration", "getSiteIcons", "getSources", "getSpeculativeParserUrls", "getStartPositionOfChar", "getStartTime", "getStats", "getStorageUpdates", "getStreamById", "getStringValue", "getSubStringLength", "getSubscription", "getSupportedExtensions", "getTexParameter", "getTime", "getTimezoneOffset", "getTotalLength", "getTrackById", "getTracks", "getTransformToElement", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours", "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", "getUint16", "getUint32", "getUint8", "getUniform", "getUniformLocation", "getUserMedia", "getValues", "getVarDate", "getVariableValue", "getVertexAttrib", "getVertexAttribOffset", "getVideoPlaybackQuality", "getVideoTracks", "getWakeLockState", "getYear", "givenName", "global", "globalAlpha", "globalCompositeOperation", "glyphOrientationHorizontal", "glyphOrientationVertical", "glyphRef", "go", "gradientTransform", "gradientUnits", "grammars", "green", "group", "groupCollapsed", "groupEnd", "hardwareConcurrency", "has", "hasAttribute", "hasAttributeNS", "hasAttributes", "hasChildNodes", "hasComposition", "hasExtension", "hasFeature", "hasFocus", "hasLayout", "hasOwnProperty", "hash", "head", "headers", "heading", "height", "hidden", "hide", "hideFocus", "high", "hint", "history", "honorificPrefix", "honorificSuffix", "horizontalOverflow", "host", "hostname", "href", "hreflang", "hspace", "html5TagCheckInerface", "htmlFor", "htmlText", "httpEquiv", "hwTimestamp", "hypot", "iccId", "iceConnectionState", "iceGatheringState", "icon", "id", "identifier", "identity", "ignoreBOM", "ignoreCase", "image-orientation", "image-rendering", "imageOrientation", "imageRendering", "images", "ime-mode", "imeMode", "implementation", "importKey", "importNode", "importStylesheet", "imports", "impp", "imul", "in1", "in2", "inBandMetadataTrackDispatchType", "inRange", "includes", "incremental", "indeterminate", "index", "indexNames", "indexOf", "indexedDB", "inertiaDestinationX", "inertiaDestinationY", "info", "init", "initAnimationEvent", "initBeforeLoadEvent", "initClipboardEvent", "initCloseEvent", "initCommandEvent", "initCompositionEvent", "initCustomEvent", "initData", "initDeviceMotionEvent", "initDeviceOrientationEvent", "initDragEvent", "initErrorEvent", "initEvent", "initFocusEvent", "initGestureEvent", "initHashChangeEvent", "initKeyEvent", "initKeyboardEvent", "initMSManipulationEvent", "initMessageEvent", "initMouseEvent", "initMouseScrollEvent", "initMouseWheelEvent", "initMutationEvent", "initNSMouseEvent", "initOverflowEvent", "initPageEvent", "initPageTransitionEvent", "initPointerEvent", "initPopStateEvent", "initProgressEvent", "initScrollAreaEvent", "initSimpleGestureEvent", "initStorageEvent", "initTextEvent", "initTimeEvent", "initTouchEvent", "initTransitionEvent", "initUIEvent", "initWebKitAnimationEvent", "initWebKitTransitionEvent", "initWebKitWheelEvent", "initWheelEvent", "initialTime", "initialize", "initiatorType", "inner", "innerHTML", "innerHeight", "innerText", "innerWidth", "input", "inputBuffer", "inputEncoding", "inputMethod", "insertAdjacentElement", "insertAdjacentHTML", "insertAdjacentText", "insertBefore", "insertCell", "insertData", "insertItemBefore", "insertNode", "insertRow", "insertRule", "instanceRoot", "intercept", "interimResults", "internalSubset", "intersectsNode", "interval", "invalidIteratorState", "inverse", "invertSelf", "is", "is2D", "isAlternate", "isArray", "isBingCurrentSearchDefault", "isBuffer", "isCandidateWindowVisible", "isChar", "isCollapsed", "isComposing", "isContentEditable", "isContentHandlerRegistered", "isContextLost", "isDefaultNamespace", "isDisabled", "isEnabled", "isEqual", "isEqualNode", "isExtensible", "isFinite", "isFramebuffer", "isFrozen", "isGenerator", "isId", "isInjected", "isInteger", "isMap", "isMultiLine", "isNaN", "isOpen", "isPointInFill", "isPointInPath", "isPointInRange", "isPointInStroke", "isPrefAlternate", "isPrimary", "isProgram", "isPropertyImplicit", "isProtocolHandlerRegistered", "isPrototypeOf", "isRenderbuffer", "isSafeInteger", "isSameNode", "isSealed", "isShader", "isSupported", "isTextEdit", "isTexture", "isTrusted", "isTypeSupported", "isView", "isolation", "italics", "item", "itemId", "itemProp", "itemRef", "itemScope", "itemType", "itemValue", "iterateNext", "iterator", "javaEnabled", "jobTitle", "join", "json", "justify-content", "justifyContent", "k1", "k2", "k3", "k4", "kernelMatrix", "kernelUnitLengthX", "kernelUnitLengthY", "kerning", "key", "keyCode", "keyFor", "keyIdentifier", "keyLightEnabled", "keyLocation", "keyPath", "keySystem", "keyText", "keyUsage", "keys", "keytype", "kind", "knee", "label", "labels", "lang", "language", "languages", "largeArcFlag", "lastChild", "lastElementChild", "lastEventId", "lastIndex", "lastIndexOf", "lastMatch", "lastMessageSubject", "lastMessageType", "lastModified", "lastModifiedDate", "lastPage", "lastParen", "lastState", "lastStyleSheetSet", "latitude", "layerX", "layerY", "layoutFlow", "layoutGrid", "layoutGridChar", "layoutGridLine", "layoutGridMode", "layoutGridType", "lbound", "left", "leftContext", "leftMargin", "length", "lengthAdjust", "lengthComputable", "letter-spacing", "letterSpacing", "level", "lighting-color", "lightingColor", "limitingConeAngle", "line", "line-height", "lineAlign", "lineBreak", "lineCap", "lineDashOffset", "lineHeight", "lineJoin", "lineNumber", "lineTo", "lineWidth", "linearRampToValueAtTime", "lineno", "link", "linkColor", "linkProgram", "links", "list", "list-style", "list-style-image", "list-style-position", "list-style-type", "listStyle", "listStyleImage", "listStylePosition", "listStyleType", "listener", "load", "loadEventEnd", "loadEventStart", "loadTimes", "loaded", "localDescription", "localName", "localStorage", "locale", "localeCompare", "location", "locationbar", "lock", "lockedFile", "log", "log10", "log1p", "log2", "logicalXDPI", "logicalYDPI", "longDesc", "longitude", "lookupNamespaceURI", "lookupPrefix", "loop", "loopEnd", "loopStart", "looping", "low", "lower", "lowerBound", "lowerOpen", "lowsrc", "m11", "m12", "m13", "m14", "m21", "m22", "m23", "m24", "m31", "m32", "m33", "m34", "m41", "m42", "m43", "m44", "manifest", "map", "mapping", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top", "marginBottom", "marginHeight", "marginLeft", "marginRight", "marginTop", "marginWidth", "mark", "marker", "marker-end", "marker-mid", "marker-offset", "marker-start", "markerEnd", "markerHeight", "markerMid", "markerOffset", "markerStart", "markerUnits", "markerWidth", "marks", "mask", "mask-type", "maskContentUnits", "maskType", "maskUnits", "match", "matchMedia", "matchMedium", "matches", "matrix", "matrixTransform", "max", "max-height", "max-width", "maxAlternatives", "maxChannelCount", "maxConnectionsPerServer", "maxDecibels", "maxDistance", "maxHeight", "maxLength", "maxTouchPoints", "maxValue", "maxWidth", "measure", "measureText", "media", "mediaDevices", "mediaElement", "mediaGroup", "mediaKeys", "mediaText", "meetOrSlice", "memory", "menubar", "mergeAttributes", "message", "messageClass", "messageHandlers", "metaKey", "method", "mimeType", "mimeTypes", "min", "min-height", "min-width", "minDecibels", "minHeight", "minValue", "minWidth", "miterLimit", "mix-blend-mode", "mixBlendMode", "mode", "modify", "mount", "move", "moveBy", "moveEnd", "moveFirst", "moveFocusDown", "moveFocusLeft", "moveFocusRight", "moveFocusUp", "moveNext", "moveRow", "moveStart", "moveTo", "moveToBookmark", "moveToElementText", "moveToPoint", "mozAdd", "mozAnimationStartTime", "mozAnon", "mozApps", "mozAudioCaptured", "mozAudioChannelType", "mozAutoplayEnabled", "mozCancelAnimationFrame", "mozCancelFullScreen", "mozCancelRequestAnimationFrame", "mozCaptureStream", "mozCaptureStreamUntilEnded", "mozClearDataAt", "mozContact", "mozContacts", "mozCreateFileHandle", "mozCurrentTransform", "mozCurrentTransformInverse", "mozCursor", "mozDash", "mozDashOffset", "mozDecodedFrames", "mozExitPointerLock", "mozFillRule", "mozFragmentEnd", "mozFrameDelay", "mozFullScreen", "mozFullScreenElement", "mozFullScreenEnabled", "mozGetAll", "mozGetAllKeys", "mozGetAsFile", "mozGetDataAt", "mozGetMetadata", "mozGetUserMedia", "mozHasAudio", "mozHasItem", "mozHidden", "mozImageSmoothingEnabled", "mozIndexedDB", "mozInnerScreenX", "mozInnerScreenY", "mozInputSource", "mozIsTextField", "mozItem", "mozItemCount", "mozItems", "mozLength", "mozLockOrientation", "mozMatchesSelector", "mozMovementX", "mozMovementY", "mozOpaque", "mozOrientation", "mozPaintCount", "mozPaintedFrames", "mozParsedFrames", "mozPay", "mozPointerLockElement", "mozPresentedFrames", "mozPreservesPitch", "mozPressure", "mozPrintCallback", "mozRTCIceCandidate", "mozRTCPeerConnection", "mozRTCSessionDescription", "mozRemove", "mozRequestAnimationFrame", "mozRequestFullScreen", "mozRequestPointerLock", "mozSetDataAt", "mozSetImageElement", "mozSourceNode", "mozSrcObject", "mozSystem", "mozTCPSocket", "mozTextStyle", "mozTypesAt", "mozUnlockOrientation", "mozUserCancelled", "mozVisibilityState", "msAnimation", "msAnimationDelay", "msAnimationDirection", "msAnimationDuration", "msAnimationFillMode", "msAnimationIterationCount", "msAnimationName", "msAnimationPlayState", "msAnimationStartTime", "msAnimationTimingFunction", "msBackfaceVisibility", "msBlockProgression", "msCSSOMElementFloatMetrics", "msCaching", "msCachingEnabled", "msCancelRequestAnimationFrame", "msCapsLockWarningOff", "msClearImmediate", "msClose", "msContentZoomChaining", "msContentZoomFactor", "msContentZoomLimit", "msContentZoomLimitMax", "msContentZoomLimitMin", "msContentZoomSnap", "msContentZoomSnapPoints", "msContentZoomSnapType", "msContentZooming", "msConvertURL", "msCrypto", "msDoNotTrack", "msElementsFromPoint", "msElementsFromRect", "msExitFullscreen", "msExtendedCode", "msFillRule", "msFirstPaint", "msFlex", "msFlexAlign", "msFlexDirection", "msFlexFlow", "msFlexItemAlign", "msFlexLinePack", "msFlexNegative", "msFlexOrder", "msFlexPack", "msFlexPositive", "msFlexPreferredSize", "msFlexWrap", "msFlowFrom", "msFlowInto", "msFontFeatureSettings", "msFullscreenElement", "msFullscreenEnabled", "msGetInputContext", "msGetRegionContent", "msGetUntransformedBounds", "msGraphicsTrustStatus", "msGridColumn", "msGridColumnAlign", "msGridColumnSpan", "msGridColumns", "msGridRow", "msGridRowAlign", "msGridRowSpan", "msGridRows", "msHidden", "msHighContrastAdjust", "msHyphenateLimitChars", "msHyphenateLimitLines", "msHyphenateLimitZone", "msHyphens", "msImageSmoothingEnabled", "msImeAlign", "msIndexedDB", "msInterpolationMode", "msIsStaticHTML", "msKeySystem", "msKeys", "msLaunchUri", "msLockOrientation", "msManipulationViewsEnabled", "msMatchMedia", "msMatchesSelector", "msMaxTouchPoints", "msOrientation", "msOverflowStyle", "msPerspective", "msPerspectiveOrigin", "msPlayToDisabled", "msPlayToPreferredSourceUri", "msPlayToPrimary", "msPointerEnabled", "msRegionOverflow", "msReleasePointerCapture", "msRequestAnimationFrame", "msRequestFullscreen", "msSaveBlob", "msSaveOrOpenBlob", "msScrollChaining", "msScrollLimit", "msScrollLimitXMax", "msScrollLimitXMin", "msScrollLimitYMax", "msScrollLimitYMin", "msScrollRails", "msScrollSnapPointsX", "msScrollSnapPointsY", "msScrollSnapType", "msScrollSnapX", "msScrollSnapY", "msScrollTranslation", "msSetImmediate", "msSetMediaKeys", "msSetPointerCapture", "msTextCombineHorizontal", "msTextSizeAdjust", "msToBlob", "msTouchAction", "msTouchSelect", "msTraceAsyncCallbackCompleted", "msTraceAsyncCallbackStarting", "msTraceAsyncOperationCompleted", "msTraceAsyncOperationStarting", "msTransform", "msTransformOrigin", "msTransformStyle", "msTransition", "msTransitionDelay", "msTransitionDuration", "msTransitionProperty", "msTransitionTimingFunction", "msUnlockOrientation", "msUpdateAsyncCallbackRelation", "msUserSelect", "msVisibilityState", "msWrapFlow", "msWrapMargin", "msWrapThrough", "msWriteProfilerMark", "msZoom", "msZoomTo", "mt", "multiEntry", "multiSelectionObj", "multiline", "multiple", "multiply", "multiplySelf", "mutableFile", "muted", "n", "name", "nameProp", "namedItem", "namedRecordset", "names", "namespaceURI", "namespaces", "naturalHeight", "naturalWidth", "navigate", "navigation", "navigationMode", "navigationStart", "navigator", "near", "nearestViewportElement", "negative", "netscape", "networkState", "newScale", "newTranslate", "newURL", "newValue", "newValueSpecifiedUnits", "newVersion", "newhome", "next", "nextElementSibling", "nextNode", "nextPage", "nextSibling", "nickname", "noHref", "noResize", "noShade", "noValidate", "noWrap", "nodeName", "nodeType", "nodeValue", "normalize", "normalizedPathSegList", "notationName", "notations", "note", "noteGrainOn", "noteOff", "noteOn", "now", "numOctaves", "number", "numberOfChannels", "numberOfInputs", "numberOfItems", "numberOfOutputs", "numberValue", "oMatchesSelector", "object", "object-fit", "object-position", "objectFit", "objectPosition", "objectStore", "objectStoreNames", "observe", "of", "offscreenBuffering", "offset", "offsetHeight", "offsetLeft", "offsetNode", "offsetParent", "offsetTop", "offsetWidth", "offsetX", "offsetY", "ok", "oldURL", "oldValue", "oldVersion", "olderShadowRoot", "onLine", "onabort", "onactivate", "onactive", "onaddstream", "onaddtrack", "onafterprint", "onafterscriptexecute", "onafterupdate", "onaudioend", "onaudioprocess", "onaudiostart", "onautocomplete", "onautocompleteerror", "onbeforeactivate", "onbeforecopy", "onbeforecut", "onbeforedeactivate", "onbeforeeditfocus", "onbeforepaste", "onbeforeprint", "onbeforescriptexecute", "onbeforeunload", "onbeforeupdate", "onblocked", "onblur", "onbounce", "onboundary", "oncached", "oncancel", "oncandidatewindowhide", "oncandidatewindowshow", "oncandidatewindowupdate", "oncanplay", "oncanplaythrough", "oncellchange", "onchange", "onchargingchange", "onchargingtimechange", "onchecking", "onclick", "onclose", "oncompassneedscalibration", "oncomplete", "oncontextmenu", "oncontrolselect", "oncopy", "oncuechange", "oncut", "ondataavailable", "ondatachannel", "ondatasetchanged", "ondatasetcomplete", "ondblclick", "ondeactivate", "ondevicelight", "ondevicemotion", "ondeviceorientation", "ondeviceproximity", "ondischargingtimechange", "ondisplay", "ondownloading", "ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover", "ondragstart", "ondrop", "ondurationchange", "onemptied", "onencrypted", "onend", "onended", "onenter", "onerror", "onerrorupdate", "onexit", "onfilterchange", "onfinish", "onfocus", "onfocusin", "onfocusout", "onfullscreenchange", "onfullscreenerror", "ongesturechange", "ongestureend", "ongesturestart", "ongotpointercapture", "onhashchange", "onhelp", "onicecandidate", "oniceconnectionstatechange", "oninactive", "oninput", "oninvalid", "onkeydown", "onkeypress", "onkeyup", "onlanguagechange", "onlayoutcomplete", "onlevelchange", "onload", "onloadeddata", "onloadedmetadata", "onloadend", "onloadstart", "onlosecapture", "onlostpointercapture", "only", "onmark", "onmessage", "onmousedown", "onmouseenter", "onmouseleave", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmousewheel", "onmove", "onmoveend", "onmovestart", "onmozfullscreenchange", "onmozfullscreenerror", "onmozorientationchange", "onmozpointerlockchange", "onmozpointerlockerror", "onmscontentzoom", "onmsfullscreenchange", "onmsfullscreenerror", "onmsgesturechange", "onmsgesturedoubletap", "onmsgestureend", "onmsgesturehold", "onmsgesturestart", "onmsgesturetap", "onmsgotpointercapture", "onmsinertiastart", "onmslostpointercapture", "onmsmanipulationstatechanged", "onmsneedkey", "onmsorientationchange", "onmspointercancel", "onmspointerdown", "onmspointerenter", "onmspointerhover", "onmspointerleave", "onmspointermove", "onmspointerout", "onmspointerover", "onmspointerup", "onmssitemodejumplistitemremoved", "onmsthumbnailclick", "onnegotiationneeded", "onnomatch", "onnoupdate", "onobsolete", "onoffline", "ononline", "onopen", "onorientationchange", "onpagechange", "onpagehide", "onpageshow", "onpaste", "onpause", "onplay", "onplaying", "onpluginstreamstart", "onpointercancel", "onpointerdown", "onpointerenter", "onpointerleave", "onpointerlockchange", "onpointerlockerror", "onpointermove", "onpointerout", "onpointerover", "onpointerup", "onpopstate", "onprogress", "onpropertychange", "onratechange", "onreadystatechange", "onremovestream", "onremovetrack", "onreset", "onresize", "onresizeend", "onresizestart", "onresourcetimingbufferfull", "onresult", "onresume", "onrowenter", "onrowexit", "onrowsdelete", "onrowsinserted", "onscroll", "onsearch", "onseeked", "onseeking", "onselect", "onselectionchange", "onselectstart", "onshow", "onsignalingstatechange", "onsoundend", "onsoundstart", "onspeechend", "onspeechstart", "onstalled", "onstart", "onstatechange", "onstop", "onstorage", "onstoragecommit", "onsubmit", "onsuccess", "onsuspend", "ontextinput", "ontimeout", "ontimeupdate", "ontoggle", "ontouchcancel", "ontouchend", "ontouchmove", "ontouchstart", "ontransitionend", "onunload", "onupdateready", "onupgradeneeded", "onuserproximity", "onversionchange", "onvoiceschanged", "onvolumechange", "onwaiting", "onwarning", "onwebkitanimationend", "onwebkitanimationiteration", "onwebkitanimationstart", "onwebkitcurrentplaybacktargetiswirelesschanged", "onwebkitfullscreenchange", "onwebkitfullscreenerror", "onwebkitkeyadded", "onwebkitkeyerror", "onwebkitkeymessage", "onwebkitneedkey", "onwebkitorientationchange", "onwebkitplaybacktargetavailabilitychanged", "onwebkitpointerlockchange", "onwebkitpointerlockerror", "onwebkitresourcetimingbufferfull", "onwebkittransitionend", "onwheel", "onzoom", "opacity", "open", "openCursor", "openDatabase", "openKeyCursor", "opener", "opera", "operationType", "operator", "opr", "optimum", "options", "order", "orderX", "orderY", "ordered", "org", "orient", "orientAngle", "orientType", "orientation", "origin", "originalTarget", "orphans", "oscpu", "outerHTML", "outerHeight", "outerText", "outerWidth", "outline", "outline-color", "outline-offset", "outline-style", "outline-width", "outlineColor", "outlineOffset", "outlineStyle", "outlineWidth", "outputBuffer", "overflow", "overflow-x", "overflow-y", "overflowX", "overflowY", "overrideMimeType", "oversample", "ownerDocument", "ownerElement", "ownerNode", "ownerRule", "ownerSVGElement", "owningElement", "p1", "p2", "p3", "p4", "pad", "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "page", "page-break-after", "page-break-before", "page-break-inside", "pageBreakAfter", "pageBreakBefore", "pageBreakInside", "pageCount", "pageX", "pageXOffset", "pageY", "pageYOffset", "pages", "paint-order", "paintOrder", "paintRequests", "paintType", "palette", "panningModel", "parent", "parentElement", "parentNode", "parentRule", "parentStyleSheet", "parentTextEdit", "parentWindow", "parse", "parseFloat", "parseFromString", "parseInt", "participants", "password", "pasteHTML", "path", "pathLength", "pathSegList", "pathSegType", "pathSegTypeAsLetter", "pathname", "pattern", "patternContentUnits", "patternMismatch", "patternTransform", "patternUnits", "pause", "pauseAnimations", "pauseOnExit", "paused", "pending", "performance", "permission", "persisted", "personalbar", "perspective", "perspective-origin", "perspectiveOrigin", "phoneticFamilyName", "phoneticGivenName", "photo", "ping", "pitch", "pixelBottom", "pixelDepth", "pixelHeight", "pixelLeft", "pixelRight", "pixelStorei", "pixelTop", "pixelUnitToMillimeterX", "pixelUnitToMillimeterY", "pixelWidth", "placeholder", "platform", "play", "playbackRate", "playbackState", "playbackTime", "played", "plugins", "pluginspage", "pname", "pointer-events", "pointerBeforeReferenceNode", "pointerEnabled", "pointerEvents", "pointerId", "pointerLockElement", "pointerType", "points", "pointsAtX", "pointsAtY", "pointsAtZ", "polygonOffset", "pop", "popupWindowFeatures", "popupWindowName", "popupWindowURI", "port", "port1", "port2", "ports", "posBottom", "posHeight", "posLeft", "posRight", "posTop", "posWidth", "position", "positionAlign", "postError", "postMessage", "poster", "pow", "powerOff", "preMultiplySelf", "precision", "preferredStyleSheetSet", "preferredStylesheetSet", "prefix", "preload", "preserveAlpha", "preserveAspectRatio", "preserveAspectRatioString", "pressed", "pressure", "prevValue", "preventDefault", "preventExtensions", "previousElementSibling", "previousNode", "previousPage", "previousScale", "previousSibling", "previousTranslate", "primaryKey", "primitiveType", "primitiveUnits", "principals", "print", "privateKey", "probablySupportsContext", "process", "processIceMessage", "product", "productSub", "profile", "profileEnd", "profiles", "prompt", "properties", "propertyIsEnumerable", "propertyName", "protocol", "protocolLong", "prototype", "pseudoClass", "pseudoElement", "publicId", "publicKey", "published", "push", "pushNotification", "pushState", "put", "putImageData", "quadraticCurveTo", "qualifier", "queryCommandEnabled", "queryCommandIndeterm", "queryCommandState", "queryCommandSupported", "queryCommandText", "queryCommandValue", "querySelector", "querySelectorAll", "quote", "quotes", "r", "r1", "r2", "race", "radiogroup", "radiusX", "radiusY", "random", "range", "rangeCount", "rangeMax", "rangeMin", "rangeOffset", "rangeOverflow", "rangeParent", "rangeUnderflow", "rate", "ratio", "raw", "read", "readAsArrayBuffer", "readAsBinaryString", "readAsBlob", "readAsDataURL", "readAsText", "readOnly", "readPixels", "readReportRequested", "readyState", "reason", "reboot", "receiver", "receivers", "recordNumber", "recordset", "rect", "red", "redirectCount", "redirectEnd", "redirectStart", "reduce", "reduceRight", "reduction", "refDistance", "refX", "refY", "referenceNode", "referrer", "refresh", "region", "regionAnchorX", "regionAnchorY", "regionId", "regions", "register", "registerContentHandler", "registerElement", "registerProtocolHandler", "reject", "rel", "relList", "relatedNode", "relatedTarget", "release", "releaseCapture", "releaseEvents", "releasePointerCapture", "releaseShaderCompiler", "reliable", "reload", "remainingSpace", "remoteDescription", "remove", "removeAllRanges", "removeAttribute", "removeAttributeNS", "removeAttributeNode", "removeBehavior", "removeChild", "removeCue", "removeEventListener", "removeFilter", "removeImport", "removeItem", "removeListener", "removeNamedItem", "removeNamedItemNS", "removeNode", "removeParameter", "removeProperty", "removeRange", "removeRegion", "removeRule", "removeSiteSpecificTrackingException", "removeSourceBuffer", "removeStream", "removeTrack", "removeVariable", "removeWakeLockListener", "removeWebWideTrackingException", "removedNodes", "renderbufferStorage", "renderedBuffer", "renderingMode", "repeat", "replace", "replaceAdjacentText", "replaceChild", "replaceData", "replaceId", "replaceItem", "replaceNode", "replaceState", "replaceTrack", "replaceWholeText", "reportValidity", "requestAnimationFrame", "requestAutocomplete", "requestData", "requestFullscreen", "requestMediaKeySystemAccess", "requestPermission", "requestPointerLock", "requestStart", "requestingWindow", "required", "requiredExtensions", "requiredFeatures", "reset", "resetTransform", "resize", "resizeBy", "resizeTo", "resolve", "response", "responseBody", "responseEnd", "responseStart", "responseText", "responseType", "responseURL", "responseXML", "restore", "result", "resultType", "resume", "returnValue", "rev", "reverse", "reversed", "revocable", "revokeObjectURL", "rgbColor", "right", "rightContext", "rightMargin", "rolloffFactor", "root", "rootElement", "rotate", "rotateAxisAngle", "rotateAxisAngleSelf", "rotateFromVector", "rotateFromVectorSelf", "rotateSelf", "rotation", "rotationRate", "round", "rowIndex", "rowSpan", "rows", "rubyAlign", "rubyOverhang", "rubyPosition", "rules", "runtime", "runtimeStyle", "rx", "ry", "safari", "sampleCoverage", "sampleRate", "sandbox", "save", "scale", "scale3d", "scale3dSelf", "scaleNonUniform", "scaleNonUniformSelf", "scaleSelf", "scheme", "scissor", "scope", "scopeName", "scoped", "screen", "screenBrightness", "screenEnabled", "screenLeft", "screenPixelToMillimeterX", "screenPixelToMillimeterY", "screenTop", "screenX", "screenY", "scripts", "scroll", "scroll-behavior", "scrollAmount", "scrollBehavior", "scrollBy", "scrollByLines", "scrollByPages", "scrollDelay", "scrollHeight", "scrollIntoView", "scrollIntoViewIfNeeded", "scrollLeft", "scrollLeftMax", "scrollMaxX", "scrollMaxY", "scrollTo", "scrollTop", "scrollTopMax", "scrollWidth", "scrollX", "scrollY", "scrollbar3dLightColor", "scrollbarArrowColor", "scrollbarBaseColor", "scrollbarDarkShadowColor", "scrollbarFaceColor", "scrollbarHighlightColor", "scrollbarShadowColor", "scrollbarTrackColor", "scrollbars", "scrolling", "sdp", "sdpMLineIndex", "sdpMid", "seal", "search", "searchBox", "searchBoxJavaBridge_", "searchParams", "sectionRowIndex", "secureConnectionStart", "security", "seed", "seekable", "seeking", "select", "selectAllChildren", "selectNode", "selectNodeContents", "selectNodes", "selectSingleNode", "selectSubString", "selected", "selectedIndex", "selectedOptions", "selectedStyleSheetSet", "selectedStylesheetSet", "selection", "selectionDirection", "selectionEnd", "selectionStart", "selector", "selectorText", "self", "send", "sendAsBinary", "sendBeacon", "sender", "sentTimestamp", "separator", "serializeToString", "serviceWorker", "sessionId", "sessionStorage", "set", "setActive", "setAlpha", "setAttribute", "setAttributeNS", "setAttributeNode", "setAttributeNodeNS", "setBaseAndExtent", "setBingCurrentSearchDefault", "setCapture", "setColor", "setCompositeOperation", "setCurrentTime", "setCustomValidity", "setData", "setDate", "setDragImage", "setEnd", "setEndAfter", "setEndBefore", "setEndPoint", "setFillColor", "setFilterRes", "setFloat32", "setFloat64", "setFloatValue", "setFullYear", "setHours", "setImmediate", "setInt16", "setInt32", "setInt8", "setInterval", "setItem", "setLineCap", "setLineDash", "setLineJoin", "setLineWidth", "setLocalDescription", "setMatrix", "setMatrixValue", "setMediaKeys", "setMilliseconds", "setMinutes", "setMiterLimit", "setMonth", "setNamedItem", "setNamedItemNS", "setNonUserCodeExceptions", "setOrientToAngle", "setOrientToAuto", "setOrientation", "setOverrideHistoryNavigationMode", "setPaint", "setParameter", "setPeriodicWave", "setPointerCapture", "setPosition", "setPreference", "setProperty", "setPrototypeOf", "setRGBColor", "setRGBColorICCColor", "setRadius", "setRangeText", "setRemoteDescription", "setRequestHeader", "setResizable", "setResourceTimingBufferSize", "setRotate", "setScale", "setSeconds", "setSelectionRange", "setServerCertificate", "setShadow", "setSkewX", "setSkewY", "setStart", "setStartAfter", "setStartBefore", "setStdDeviation", "setStringValue", "setStrokeColor", "setSuggestResult", "setTargetAtTime", "setTargetValueAtTime", "setTime", "setTimeout", "setTransform", "setTranslate", "setUTCDate", "setUTCFullYear", "setUTCHours", "setUTCMilliseconds", "setUTCMinutes", "setUTCMonth", "setUTCSeconds", "setUint16", "setUint32", "setUint8", "setUri", "setValueAtTime", "setValueCurveAtTime", "setVariable", "setVelocity", "setVersion", "setYear", "settingName", "settingValue", "sex", "shaderSource", "shadowBlur", "shadowColor", "shadowOffsetX", "shadowOffsetY", "shadowRoot", "shape", "shape-rendering", "shapeRendering", "sheet", "shift", "shiftKey", "shiftLeft", "show", "showHelp", "showModal", "showModalDialog", "showModelessDialog", "showNotification", "sidebar", "sign", "signalingState", "sin", "singleNodeValue", "sinh", "size", "sizeToContent", "sizes", "skewX", "skewXSelf", "skewY", "skewYSelf", "slice", "slope", "small", "smil", "smoothingTimeConstant", "snapToLines", "snapshotItem", "snapshotLength", "some", "sort", "source", "sourceBuffer", "sourceBuffers", "sourceIndex", "spacing", "span", "speakAs", "speaking", "specified", "specularConstant", "specularExponent", "speechSynthesis", "speed", "speedOfSound", "spellcheck", "splice", "split", "splitText", "spreadMethod", "sqrt", "src", "srcElement", "srcFilter", "srcUrn", "srcdoc", "srclang", "srcset", "stack", "stackTraceLimit", "stacktrace", "standalone", "standby", "start", "startContainer", "startIce", "startOffset", "startRendering", "startTime", "startsWith", "state", "status", "statusMessage", "statusText", "statusbar", "stdDeviationX", "stdDeviationY", "stencilFunc", "stencilFuncSeparate", "stencilMask", "stencilMaskSeparate", "stencilOp", "stencilOpSeparate", "step", "stepDown", "stepMismatch", "stepUp", "sticky", "stitchTiles", "stop", "stop-color", "stop-opacity", "stopColor", "stopImmediatePropagation", "stopOpacity", "stopPropagation", "storageArea", "storageName", "storageStatus", "storeSiteSpecificTrackingException", "storeWebWideTrackingException", "stpVersion", "stream", "strike", "stringValue", "stringify", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "strokeDasharray", "strokeDashoffset", "strokeLinecap", "strokeLinejoin", "strokeMiterlimit", "strokeOpacity", "strokeRect", "strokeStyle", "strokeText", "strokeWidth", "style", "styleFloat", "styleMedia", "styleSheet", "styleSheetSets", "styleSheets", "sub", "subarray", "subject", "submit", "subscribe", "substr", "substring", "substringData", "subtle", "suffix", "suffixes", "summary", "sup", "supports", "surfaceScale", "surroundContents", "suspend", "suspendRedraw", "swapCache", "swapNode", "sweepFlag", "symbols", "system", "systemCode", "systemId", "systemLanguage", "systemXDPI", "systemYDPI", "tBodies", "tFoot", "tHead", "tabIndex", "table", "table-layout", "tableLayout", "tableValues", "tag", "tagName", "tagUrn", "tags", "taintEnabled", "takeRecords", "tan", "tanh", "target", "targetElement", "targetTouches", "targetX", "targetY", "tel", "terminate", "test", "texImage2D", "texParameterf", "texParameteri", "texSubImage2D", "text", "text-align", "text-anchor", "text-decoration", "text-decoration-color", "text-decoration-line", "text-decoration-style", "text-indent", "text-overflow", "text-rendering", "text-shadow", "text-transform", "textAlign", "textAlignLast", "textAnchor", "textAutospace", "textBaseline", "textContent", "textDecoration", "textDecorationBlink", "textDecorationColor", "textDecorationLine", "textDecorationLineThrough", "textDecorationNone", "textDecorationOverline", "textDecorationStyle", "textDecorationUnderline", "textIndent", "textJustify", "textJustifyTrim", "textKashida", "textKashidaSpace", "textLength", "textOverflow", "textRendering", "textShadow", "textTracks", "textTransform", "textUnderlinePosition", "then", "threadId", "threshold", "tiltX", "tiltY", "time", "timeEnd", "timeStamp", "timeout", "timestamp", "timestampOffset", "timing", "title", "toArray", "toBlob", "toDataURL", "toDateString", "toElement", "toExponential", "toFixed", "toFloat32Array", "toFloat64Array", "toGMTString", "toISOString", "toJSON", "toLocaleDateString", "toLocaleFormat", "toLocaleLowerCase", "toLocaleString", "toLocaleTimeString", "toLocaleUpperCase", "toLowerCase", "toMethod", "toPrecision", "toSdp", "toSource", "toStaticHTML", "toString", "toStringTag", "toTimeString", "toUTCString", "toUpperCase", "toggle", "toggleLongPressEnabled", "tooLong", "toolbar", "top", "topMargin", "total", "totalFrameDelay", "totalVideoFrames", "touchAction", "touches", "trace", "track", "transaction", "transactions", "transform", "transform-origin", "transform-style", "transformOrigin", "transformPoint", "transformString", "transformStyle", "transformToDocument", "transformToFragment", "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function", "transitionDelay", "transitionDuration", "transitionProperty", "transitionTimingFunction", "translate", "translateSelf", "translationX", "translationY", "trim", "trimLeft", "trimRight", "trueSpeed", "trunc", "truncate", "type", "typeDetail", "typeMismatch", "typeMustMatch", "types", "ubound", "undefined", "unescape", "uneval", "unicode-bidi", "unicodeBidi", "uniform1f", "uniform1fv", "uniform1i", "uniform1iv", "uniform2f", "uniform2fv", "uniform2i", "uniform2iv", "uniform3f", "uniform3fv", "uniform3i", "uniform3iv", "uniform4f", "uniform4fv", "uniform4i", "uniform4iv", "uniformMatrix2fv", "uniformMatrix3fv", "uniformMatrix4fv", "unique", "uniqueID", "uniqueNumber", "unitType", "units", "unloadEventEnd", "unloadEventStart", "unlock", "unmount", "unobserve", "unpause", "unpauseAnimations", "unreadCount", "unregister", "unregisterContentHandler", "unregisterProtocolHandler", "unscopables", "unselectable", "unshift", "unsubscribe", "unsuspendRedraw", "unsuspendRedrawAll", "unwatch", "unwrapKey", "update", "updateCommands", "updateIce", "updateInterval", "updateSettings", "updated", "updating", "upload", "upper", "upperBound", "upperOpen", "uri", "url", "urn", "urns", "usages", "useCurrentView", "useMap", "useProgram", "usedSpace", "userAgent", "userLanguage", "username", "v8BreakIterator", "vAlign", "vLink", "valid", "validateProgram", "validationMessage", "validity", "value", "valueAsDate", "valueAsNumber", "valueAsString", "valueInSpecifiedUnits", "valueMissing", "valueOf", "valueText", "valueType", "values", "vector-effect", "vectorEffect", "velocityAngular", "velocityExpansion", "velocityX", "velocityY", "vendor", "vendorSub", "verify", "version", "vertexAttrib1f", "vertexAttrib1fv", "vertexAttrib2f", "vertexAttrib2fv", "vertexAttrib3f", "vertexAttrib3fv", "vertexAttrib4f", "vertexAttrib4fv", "vertexAttribDivisorANGLE", "vertexAttribPointer", "vertical", "vertical-align", "verticalAlign", "verticalOverflow", "vibrate", "videoHeight", "videoTracks", "videoWidth", "view", "viewBox", "viewBoxString", "viewTarget", "viewTargetString", "viewport", "viewportAnchorX", "viewportAnchorY", "viewportElement", "visibility", "visibilityState", "visible", "vlinkColor", "voice", "volume", "vrml", "vspace", "w", "wand", "warn", "wasClean", "watch", "watchPosition", "webdriver", "webkitAddKey", "webkitAnimation", "webkitAnimationDelay", "webkitAnimationDirection", "webkitAnimationDuration", "webkitAnimationFillMode", "webkitAnimationIterationCount", "webkitAnimationName", "webkitAnimationPlayState", "webkitAnimationTimingFunction", "webkitAppearance", "webkitAudioContext", "webkitAudioDecodedByteCount", "webkitAudioPannerNode", "webkitBackfaceVisibility", "webkitBackground", "webkitBackgroundAttachment", "webkitBackgroundClip", "webkitBackgroundColor", "webkitBackgroundImage", "webkitBackgroundOrigin", "webkitBackgroundPosition", "webkitBackgroundPositionX", "webkitBackgroundPositionY", "webkitBackgroundRepeat", "webkitBackgroundSize", "webkitBackingStorePixelRatio", "webkitBorderImage", "webkitBorderImageOutset", "webkitBorderImageRepeat", "webkitBorderImageSlice", "webkitBorderImageSource", "webkitBorderImageWidth", "webkitBoxAlign", "webkitBoxDirection", "webkitBoxFlex", "webkitBoxOrdinalGroup", "webkitBoxOrient", "webkitBoxPack", "webkitBoxSizing", "webkitCancelAnimationFrame", "webkitCancelFullScreen", "webkitCancelKeyRequest", "webkitCancelRequestAnimationFrame", "webkitClearResourceTimings", "webkitClosedCaptionsVisible", "webkitConvertPointFromNodeToPage", "webkitConvertPointFromPageToNode", "webkitCreateShadowRoot", "webkitCurrentFullScreenElement", "webkitCurrentPlaybackTargetIsWireless", "webkitDirectionInvertedFromDevice", "webkitDisplayingFullscreen", "webkitEnterFullScreen", "webkitEnterFullscreen", "webkitExitFullScreen", "webkitExitFullscreen", "webkitExitPointerLock", "webkitFullScreenKeyboardInputAllowed", "webkitFullscreenElement", "webkitFullscreenEnabled", "webkitGenerateKeyRequest", "webkitGetAsEntry", "webkitGetDatabaseNames", "webkitGetEntries", "webkitGetEntriesByName", "webkitGetEntriesByType", "webkitGetFlowByName", "webkitGetGamepads", "webkitGetImageDataHD", "webkitGetNamedFlows", "webkitGetRegionFlowRanges", "webkitGetUserMedia", "webkitHasClosedCaptions", "webkitHidden", "webkitIDBCursor", "webkitIDBDatabase", "webkitIDBDatabaseError", "webkitIDBDatabaseException", "webkitIDBFactory", "webkitIDBIndex", "webkitIDBKeyRange", "webkitIDBObjectStore", "webkitIDBRequest", "webkitIDBTransaction", "webkitImageSmoothingEnabled", "webkitIndexedDB", "webkitInitMessageEvent", "webkitIsFullScreen", "webkitKeys", "webkitLineDashOffset", "webkitLockOrientation", "webkitMatchesSelector", "webkitMediaStream", "webkitNotifications", "webkitOfflineAudioContext", "webkitOrientation", "webkitPeerConnection00", "webkitPersistentStorage", "webkitPointerLockElement", "webkitPostMessage", "webkitPreservesPitch", "webkitPutImageDataHD", "webkitRTCPeerConnection", "webkitRegionOverset", "webkitRequestAnimationFrame", "webkitRequestFileSystem", "webkitRequestFullScreen", "webkitRequestFullscreen", "webkitRequestPointerLock", "webkitResolveLocalFileSystemURL", "webkitSetMediaKeys", "webkitSetResourceTimingBufferSize", "webkitShadowRoot", "webkitShowPlaybackTargetPicker", "webkitSlice", "webkitSpeechGrammar", "webkitSpeechGrammarList", "webkitSpeechRecognition", "webkitSpeechRecognitionError", "webkitSpeechRecognitionEvent", "webkitStorageInfo", "webkitSupportsFullscreen", "webkitTemporaryStorage", "webkitTextSizeAdjust", "webkitTransform", "webkitTransformOrigin", "webkitTransition", "webkitTransitionDelay", "webkitTransitionDuration", "webkitTransitionProperty", "webkitTransitionTimingFunction", "webkitURL", "webkitUnlockOrientation", "webkitUserSelect", "webkitVideoDecodedByteCount", "webkitVisibilityState", "webkitWirelessVideoPlaybackDisabled", "webkitdropzone", "webstore", "weight", "whatToShow", "wheelDelta", "wheelDeltaX", "wheelDeltaY", "which", "white-space", "whiteSpace", "wholeText", "widows", "width", "will-change", "willChange", "willValidate", "window", "withCredentials", "word-break", "word-spacing", "word-wrap", "wordBreak", "wordSpacing", "wordWrap", "wrap", "wrapKey", "write", "writeln", "writingMode", "x", "x1", "x2", "xChannelSelector", "xmlEncoding", "xmlStandalone", "xmlVersion", "xmlbase", "xmllang", "xmlspace", "y", "y1", "y2", "yChannelSelector", "yandex", "z", "z-index", "zIndex", "zoom", "zoomAndPan", "zoomRectScreen" ] } UglifyJS2-2.8.29/tools/exports.js000066400000000000000000000012601312030606600165700ustar00rootroot00000000000000exports["Compressor"] = Compressor; exports["DefaultsError"] = DefaultsError; exports["Dictionary"] = Dictionary; exports["JS_Parse_Error"] = JS_Parse_Error; exports["MAP"] = MAP; exports["OutputStream"] = OutputStream; exports["SourceMap"] = SourceMap; exports["TreeTransformer"] = TreeTransformer; exports["TreeWalker"] = TreeWalker; exports["base54"] = base54; exports["defaults"] = defaults; exports["mangle_properties"] = mangle_properties; exports["merge"] = merge; exports["parse"] = parse; exports["push_uniq"] = push_uniq; exports["string_template"] = string_template; exports["tokenizer"] = tokenizer; exports["is_identifier"] = is_identifier; exports["SymbolDef"] = SymbolDef; UglifyJS2-2.8.29/tools/node.js000066400000000000000000000237221312030606600160200ustar00rootroot00000000000000// workaround for tty output truncation upon process.exit() [process.stdout, process.stderr].forEach(function(stream){ if (stream._handle && stream._handle.setBlocking) stream._handle.setBlocking(true); }); var path = require("path"); var fs = require("fs"); var UglifyJS = exports; var FILES = UglifyJS.FILES = [ "../lib/utils.js", "../lib/ast.js", "../lib/parse.js", "../lib/transform.js", "../lib/scope.js", "../lib/output.js", "../lib/compress.js", "../lib/sourcemap.js", "../lib/mozilla-ast.js", "../lib/propmangle.js", "./exports.js", ].map(function(file){ return require.resolve(file); }); new Function("MOZ_SourceMap", "exports", FILES.map(function(file){ return fs.readFileSync(file, "utf8"); }).join("\n\n"))( require("source-map"), UglifyJS ); UglifyJS.AST_Node.warn_function = function(txt) { console.error("WARN: %s", txt); }; function read_source_map(code) { var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); if (!match) { UglifyJS.AST_Node.warn("inline source map not found"); return null; } return JSON.parse(new Buffer(match[2], "base64")); } UglifyJS.minify = function(files, options) { options = UglifyJS.defaults(options, { compress : {}, fromString : false, inSourceMap : null, mangle : {}, mangleProperties : false, nameCache : null, outFileName : null, output : null, outSourceMap : null, parse : {}, sourceMapInline : false, sourceMapUrl : null, sourceRoot : null, spidermonkey : false, warnings : false, }); UglifyJS.base54.reset(); var inMap = options.inSourceMap; if (typeof inMap == "string" && inMap != "inline") { inMap = JSON.parse(fs.readFileSync(inMap, "utf8")); } // 1. parse var toplevel = null, sourcesContent = {}; if (options.spidermonkey) { if (inMap == "inline") { throw new Error("inline source map only works with built-in parser"); } toplevel = UglifyJS.AST_Node.from_mozilla_ast(files); } else { function addFile(file, fileUrl) { var code = options.fromString ? file : fs.readFileSync(file, "utf8"); if (inMap == "inline") { inMap = read_source_map(code); } sourcesContent[fileUrl] = code; toplevel = UglifyJS.parse(code, { filename: fileUrl, toplevel: toplevel, bare_returns: options.parse ? options.parse.bare_returns : undefined }); } if (!options.fromString) { files = UglifyJS.simple_glob(files); if (inMap == "inline" && files.length > 1) { throw new Error("inline source map only works with singular input"); } } [].concat(files).forEach(function (files, i) { if (typeof files === 'string') { addFile(files, options.fromString ? i : files); } else { for (var fileUrl in files) { addFile(files[fileUrl], fileUrl); } } }); } if (options.wrap) { toplevel = toplevel.wrap_commonjs(options.wrap, options.exportAll); } // 2. compress if (options.compress) { var compress = { warnings: options.warnings }; UglifyJS.merge(compress, options.compress); toplevel.figure_out_scope(options.mangle); var sq = UglifyJS.Compressor(compress); toplevel = sq.compress(toplevel); } // 3. mangle properties if (options.mangleProperties || options.nameCache) { options.mangleProperties.cache = UglifyJS.readNameCache(options.nameCache, "props"); toplevel = UglifyJS.mangle_properties(toplevel, options.mangleProperties); UglifyJS.writeNameCache(options.nameCache, "props", options.mangleProperties.cache); } // 4. mangle if (options.mangle) { toplevel.figure_out_scope(options.mangle); toplevel.compute_char_frequency(options.mangle); toplevel.mangle_names(options.mangle); } // 5. output var output = { max_line_len: 32000 }; if (options.outSourceMap || options.sourceMapInline) { output.source_map = UglifyJS.SourceMap({ // prefer outFileName, otherwise use outSourceMap without .map suffix file: options.outFileName || (typeof options.outSourceMap === 'string' ? options.outSourceMap.replace(/\.map$/i, '') : null), orig: inMap, root: options.sourceRoot }); if (options.sourceMapIncludeSources) { for (var file in sourcesContent) { if (sourcesContent.hasOwnProperty(file)) { output.source_map.get().setSourceContent(file, sourcesContent[file]); } } } } if (options.output) { UglifyJS.merge(output, options.output); } var stream = UglifyJS.OutputStream(output); toplevel.print(stream); var source_map = output.source_map; if (source_map) { source_map = source_map + ""; } var mappingUrlPrefix = "\n//# sourceMappingURL="; if (options.sourceMapInline) { stream += mappingUrlPrefix + "data:application/json;charset=utf-8;base64," + new Buffer(source_map).toString("base64"); } else if (options.outSourceMap && typeof options.outSourceMap === "string" && options.sourceMapUrl !== false) { stream += mappingUrlPrefix + (typeof options.sourceMapUrl === "string" ? options.sourceMapUrl : options.outSourceMap); } return { code : stream + "", map : source_map }; }; // UglifyJS.describe_ast = function() { // function doitem(ctor) { // var sub = {}; // ctor.SUBCLASSES.forEach(function(ctor){ // sub[ctor.TYPE] = doitem(ctor); // }); // var ret = {}; // if (ctor.SELF_PROPS.length > 0) ret.props = ctor.SELF_PROPS; // if (ctor.SUBCLASSES.length > 0) ret.sub = sub; // return ret; // } // return doitem(UglifyJS.AST_Node).sub; // } UglifyJS.describe_ast = function() { var out = UglifyJS.OutputStream({ beautify: true }); function doitem(ctor) { out.print("AST_" + ctor.TYPE); var props = ctor.SELF_PROPS.filter(function(prop){ return !/^\$/.test(prop); }); if (props.length > 0) { out.space(); out.with_parens(function(){ props.forEach(function(prop, i){ if (i) out.space(); out.print(prop); }); }); } if (ctor.documentation) { out.space(); out.print_string(ctor.documentation); } if (ctor.SUBCLASSES.length > 0) { out.space(); out.with_block(function(){ ctor.SUBCLASSES.forEach(function(ctor, i){ out.indent(); doitem(ctor); out.newline(); }); }); } }; doitem(UglifyJS.AST_Node); return out + ""; }; function readReservedFile(filename, reserved) { if (!reserved) { reserved = { vars: [], props: [] }; } var data = fs.readFileSync(filename, "utf8"); data = JSON.parse(data); if (data.vars) { data.vars.forEach(function(name){ UglifyJS.push_uniq(reserved.vars, name); }); } if (data.props) { data.props.forEach(function(name){ UglifyJS.push_uniq(reserved.props, name); }); } return reserved; } UglifyJS.readReservedFile = readReservedFile; UglifyJS.readDefaultReservedFile = function(reserved) { return readReservedFile(require.resolve("./domprops.json"), reserved); }; UglifyJS.readNameCache = function(filename, key) { var cache = null; if (filename) { try { var cache = fs.readFileSync(filename, "utf8"); cache = JSON.parse(cache)[key]; if (!cache) throw "init"; cache.props = UglifyJS.Dictionary.fromObject(cache.props); } catch(ex) { cache = { cname: -1, props: new UglifyJS.Dictionary() }; } } return cache; }; UglifyJS.writeNameCache = function(filename, key, cache) { if (filename) { var data; try { data = fs.readFileSync(filename, "utf8"); data = JSON.parse(data); } catch(ex) { data = {}; } data[key] = { cname: cache.cname, props: cache.props.toObject() }; fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8"); } }; // A file glob function that only supports "*" and "?" wildcards in the basename. // Example: "foo/bar/*baz??.*.js" // Argument `glob` may be a string or an array of strings. // Returns an array of strings. Garbage in, garbage out. UglifyJS.simple_glob = function simple_glob(glob) { if (Array.isArray(glob)) { return [].concat.apply([], glob.map(simple_glob)); } if (glob.match(/\*|\?/)) { var dir = path.dirname(glob); try { var entries = fs.readdirSync(dir); } catch (ex) {} if (entries) { var pattern = "^" + path.basename(glob) .replace(/[.+^$[\]\\(){}]/g, "\\$&") .replace(/\*/g, "[^/\\\\]*") .replace(/\?/g, "[^/\\\\]") + "$"; var mod = process.platform === "win32" ? "i" : ""; var rx = new RegExp(pattern, mod); var results = entries.filter(function(name) { return rx.test(name); }).map(function(name) { return path.join(dir, name); }); if (results.length) return results; } } return [ glob ]; }; UglifyJS2-2.8.29/tools/props.html000066400000000000000000000031501312030606600165570ustar00rootroot00000000000000