├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── build.yml │ ├── ci.yml │ ├── moz.yml │ └── ufuzz.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── uglifyjs ├── lib ├── ast.js ├── compress.js ├── minify.js ├── mozilla-ast.js ├── output.js ├── parse.js ├── propmangle.js ├── scope.js ├── sourcemap.js ├── transform.js └── utils.js ├── package.json ├── test ├── benchmark.js ├── compress.js ├── compress │ ├── annotations.js │ ├── arguments.js │ ├── arrays.js │ ├── arrows.js │ ├── asm.js │ ├── assignments.js │ ├── awaits.js │ ├── bigint.js │ ├── blocks.js │ ├── booleans.js │ ├── classes.js │ ├── collapse_vars.js │ ├── comparisons.js │ ├── concat-strings.js │ ├── conditionals.js │ ├── const.js │ ├── dead-code.js │ ├── debugger.js │ ├── default-values.js │ ├── destructured.js │ ├── directives.js │ ├── drop-console.js │ ├── drop-unused.js │ ├── evaluate.js │ ├── exponentiation.js │ ├── exports.js │ ├── functions.js │ ├── global_defs.js │ ├── hoist_props.js │ ├── hoist_vars.js │ ├── html_comments.js │ ├── ie.js │ ├── if_return.js │ ├── imports.js │ ├── indentation.js │ ├── issue-1034.js │ ├── issue-1041.js │ ├── issue-1052.js │ ├── issue-1105.js │ ├── issue-12.js │ ├── issue-1202.js │ ├── issue-126.js │ ├── issue-1261.js │ ├── issue-1275.js │ ├── issue-1321.js │ ├── issue-143.js │ ├── issue-1431.js │ ├── issue-1443.js │ ├── issue-1446.js │ ├── issue-1447.js │ ├── issue-1569.js │ ├── issue-1588.js │ ├── issue-1609.js │ ├── issue-1639.js │ ├── issue-1656.js │ ├── issue-1673.js │ ├── issue-1704.js │ ├── issue-1733.js │ ├── issue-1750.js │ ├── issue-1770.js │ ├── issue-1787.js │ ├── issue-1833.js │ ├── issue-1943.js │ ├── issue-208.js │ ├── issue-22.js │ ├── issue-2652.js │ ├── issue-267.js │ ├── issue-269.js │ ├── issue-2719.js │ ├── issue-281.js │ ├── issue-2871.js │ ├── issue-2989.js │ ├── issue-368.js │ ├── issue-3768.js │ ├── issue-44.js │ ├── issue-5614.js │ ├── issue-59.js │ ├── issue-597.js │ ├── issue-611.js │ ├── issue-637.js │ ├── issue-640.js │ ├── issue-747.js │ ├── issue-751.js │ ├── issue-782.js │ ├── issue-892.js │ ├── issue-913.js │ ├── issue-973.js │ ├── issue-976.js │ ├── issue-979.js │ ├── join_vars.js │ ├── keep_fargs.js │ ├── labels.js │ ├── let.js │ ├── loops.js │ ├── max_line_len.js │ ├── merge_vars.js │ ├── negate-iife.js │ ├── new.js │ ├── node_version.js │ ├── nullish.js │ ├── numbers.js │ ├── objects.js │ ├── optional-chains.js │ ├── preserve_line.js │ ├── properties.js │ ├── pure_funcs.js │ ├── pure_getters.js │ ├── reduce_vars.js │ ├── regexp.js │ ├── rename.js │ ├── rests.js │ ├── return_undefined.js │ ├── sandbox.js │ ├── sequences.js │ ├── side_effects.js │ ├── spreads.js │ ├── string-literal.js │ ├── switches.js │ ├── templates.js │ ├── transform.js │ ├── typeof.js │ ├── unicode.js │ ├── varify.js │ ├── webkit.js │ ├── wrap_iife.js │ └── yields.js ├── exports.js ├── fetch.js ├── input │ ├── comments │ │ └── filter.js │ ├── enclose │ │ └── input.js │ ├── global_defs │ │ ├── nested.js │ │ └── simple.js │ ├── invalid │ │ ├── assign_1.js │ │ ├── assign_2.js │ │ ├── assign_3.js │ │ ├── assign_4.js │ │ ├── assign_5.js │ │ ├── delete.js │ │ ├── destructured_var.js │ │ ├── dot_1.js │ │ ├── dot_2.js │ │ ├── dot_3.js │ │ ├── else.js │ │ ├── eof.js │ │ ├── for-await.js │ │ ├── for-in_1.js │ │ ├── for-in_2.js │ │ ├── for-of_1.js │ │ ├── for-of_2.js │ │ ├── function_1.js │ │ ├── function_2.js │ │ ├── function_3.js │ │ ├── loop-no-body.js │ │ ├── object.js │ │ ├── optional-template.js │ │ ├── return.js │ │ ├── simple.js │ │ ├── switch.js │ │ ├── tab.js │ │ ├── try.js │ │ └── var.js │ ├── issue-1236 │ │ ├── simple.js │ │ └── simple.js.map │ ├── issue-1242 │ │ ├── bar.es5 │ │ ├── baz.es5 │ │ ├── foo.es5 │ │ └── qux.js │ ├── issue-1323 │ │ └── sample.js │ ├── issue-1431 │ │ └── sample.js │ ├── issue-1482 │ │ ├── beautify.js │ │ ├── braces.js │ │ ├── default.js │ │ └── input.js │ ├── issue-1632 │ │ └── ^{foo}[bar](baz)+$.js │ ├── issue-2082 │ │ ├── sample.js │ │ └── sample.js.map │ ├── issue-2310 │ │ └── input.js │ ├── issue-3040 │ │ ├── expect.js │ │ ├── input.js │ │ └── input.js.map │ ├── issue-3294 │ │ ├── input.js │ │ └── output.js │ ├── issue-3315 │ │ ├── config.json │ │ └── input.js │ ├── issue-3441 │ │ └── input.js │ ├── issue-505 │ │ ├── input.js │ │ └── output.js │ ├── issue-520 │ │ ├── input.js │ │ └── output.js │ ├── module │ │ ├── expect.js │ │ └── input.js │ ├── reduce │ │ ├── destructured_assign.js │ │ ├── destructured_assign.reduced.js │ │ ├── destructured_catch.js │ │ ├── destructured_catch.reduced.js │ │ ├── diff_error.js │ │ ├── diff_error.reduced.js │ │ ├── export_default.js │ │ ├── label.js │ │ ├── label.reduced.js │ │ ├── setter.js │ │ ├── setter.reduced.js │ │ ├── unsafe_math.js │ │ └── unsafe_math.reduced.js │ └── rename │ │ └── input.js ├── jetstream.js ├── mocha.js ├── mocha │ ├── arguments.js │ ├── awaits.js │ ├── bug-report.js │ ├── cli.js │ ├── comments.js │ ├── directives.js │ ├── exports.js │ ├── getter-setter.js │ ├── glob.js │ ├── imports.js │ ├── let.js │ ├── line-endings.js │ ├── minify-file-map.js │ ├── minify.js │ ├── number-literal.js │ ├── operator.js │ ├── parentheses.js │ ├── reduce.js │ ├── sourcemaps.js │ ├── spidermonkey.js │ ├── string-literal.js │ ├── templates.js │ ├── tokens.js │ ├── with.js │ └── yields.js ├── mozilla-ast.js ├── node.js ├── reduce.js ├── release │ ├── acorn.sh │ ├── benchmark.js │ ├── bootstrap.sh │ ├── buble.sh │ ├── butternut.sh │ ├── install.sh │ ├── jetstream.js │ ├── mathjs.sh │ ├── rollup-es.sh │ ├── rollup-ts.sh │ ├── run.js │ ├── sucrase.sh │ └── web-tooling-benchmark.sh ├── sandbox.js └── ufuzz │ ├── actions.js │ ├── index.js │ ├── job.js │ └── options.json └── tools ├── domprops.html ├── domprops.json ├── exports.js ├── node.js └── tty.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js text eol=lf 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | **Uglify version (`uglifyjs -V`)** 13 | 14 | **JavaScript input** 15 | 16 | 29 | 30 | **The `uglifyjs` CLI command executed or `minify()` options used.** 31 | 32 | 45 | 46 | **JavaScript output or error produced.** 47 | 48 | 52 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build testing 2 | on: 3 | pull_request: 4 | push: 5 | branches: [ master ] 6 | jobs: 7 | ufuzz: 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | options: 12 | - '--ie -c' 13 | - '-mb braces' 14 | - '--toplevel -mc' 15 | - '-p acorn -mco spidermonkey' 16 | - '-mc passes=3,pure_getters,unsafe' 17 | script: 18 | - acorn.sh 19 | - bootstrap.sh 20 | - buble.sh 21 | - butternut.sh 22 | - mathjs.sh 23 | - rollup-es.sh 24 | - rollup-ts.sh 25 | - sucrase.sh 26 | - web-tooling-benchmark.sh 27 | include: 28 | - node: '14' 29 | script: acorn.sh 30 | - node: '14' 31 | script: bootstrap.sh 32 | - node: '14' 33 | script: buble.sh 34 | - node: '14' 35 | script: butternut.sh 36 | - node: '14' 37 | script: mathjs.sh 38 | - node: '8' 39 | script: rollup-es.sh 40 | - node: '14' 41 | script: rollup-ts.sh 42 | - node: '14' 43 | script: sucrase.sh 44 | - node: '14' 45 | script: web-tooling-benchmark.sh 46 | name: ${{ matrix.script }} ${{ matrix.options }} 47 | runs-on: ubuntu-latest 48 | env: 49 | NODE: ${{ matrix.node }} 50 | OPTIONS: ${{ matrix.options }} 51 | SCRIPT: ${{ matrix.script }} 52 | steps: 53 | - uses: actions/checkout@v4 54 | - name: Perform uglify, build & test 55 | shell: bash 56 | run: | 57 | . ./test/release/install.sh 58 | ./test/release/$SCRIPT $OPTIONS 59 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | branches: [ master ] 6 | jobs: 7 | test: 8 | strategy: 9 | matrix: 10 | node: [ '0.10', '0.12', '4', '6', '8', '10', '12', '14', '16', '18', '20' ] 11 | os: [ ubuntu-latest, windows-latest ] 12 | script: [ compress, mocha, release/benchmark, release/jetstream ] 13 | name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }} 14 | runs-on: ${{ matrix.os }} 15 | env: 16 | NODE: ${{ matrix.node }} 17 | TYPE: ${{ matrix.script }} 18 | UGLIFY_GITHUB_LAG: 10000 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: actions/cache@v4 22 | with: 23 | path: tmp 24 | key: tmp ${{ matrix.script }} 25 | - name: Patch OpenSSL on Ubuntu 26 | if: runner.os == 'Linux' 27 | shell: bash 28 | run: | 29 | sudo sed -i 's/providers = provider_sect/# providers = provider_sect/' /etc/ssl/openssl.cnf 30 | - name: Perform tests 31 | shell: bash 32 | run: | 33 | . ./test/release/install.sh 34 | node test/$TYPE 35 | -------------------------------------------------------------------------------- /.github/workflows/moz.yml: -------------------------------------------------------------------------------- 1 | name: ESTree 2 | on: 3 | pull_request: 4 | push: 5 | branches: [ master ] 6 | jobs: 7 | test: 8 | name: fuzzing 9 | runs-on: ubuntu-latest 10 | env: 11 | NODE: 22 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Perform tests 15 | shell: bash 16 | run: | 17 | . ./test/release/install.sh 18 | node test/mozilla-ast.js 5000 19 | -------------------------------------------------------------------------------- /.github/workflows/ufuzz.yml: -------------------------------------------------------------------------------- 1 | name: Fuzzing 2 | on: 3 | pull_request: 4 | schedule: 5 | - cron: '*/15 * * * *' 6 | workflow_dispatch: 7 | workflow_run: 8 | branches: [ master ] 9 | types: [ completed ] 10 | workflows: [ 'Build testing', CI ] 11 | env: 12 | BASE_URL: https://api.github.com/repos/${{ github.repository }} 13 | TOKEN: ${{ github.token }} 14 | jobs: 15 | ufuzz: 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | include: 20 | - node: '16' 21 | os: macos-latest 22 | - node: '12' 23 | os: ubuntu-latest 24 | - node: '8' 25 | os: ubuntu-latest 26 | - node: '12' 27 | os: windows-latest 28 | - node: '8' 29 | os: windows-latest 30 | name: ${{ matrix.node }} ${{ matrix.os }} 31 | runs-on: ${{ matrix.os }} 32 | env: 33 | NODE: ${{ matrix.node }} 34 | steps: 35 | - uses: actions/checkout@v4 36 | - name: Perform fuzzing 37 | shell: bash 38 | run: | 39 | . ./test/release/install.sh 40 | if [[ $GITHUB_EVENT_NAME == "pull_request" ]]; then 41 | node test/ufuzz/job 5000 42 | else 43 | node test/ufuzz/job $BASE_URL $TOKEN $GITHUB_RUN_NUMBER 44 | fi 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /npm-debug.log 3 | tmp/ 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | ## Documentation 5 | 6 | Every new feature and API change should be accompanied by a README addition. 7 | 8 | ## Testing 9 | 10 | All features and bugs should have tests that verify the fix. You can run all 11 | tests using `npm test`. 12 | 13 | The most common type of test are tests that verify input and output of the 14 | Uglify transforms. These tests exist in `test/compress`. New tests can be added 15 | either to an existing file or in a new file `issue-xxx.js`. 16 | 17 | Tests that cannot be expressed as a simple AST can be found in `test/mocha`. 18 | 19 | ## Code style 20 | 21 | - File encoding must be `UTF-8`. 22 | - `LF` is always used as a line ending. 23 | - Statements end with semicolons. 24 | - Indentation uses 4 spaces, switch `case` 2 spaces. 25 | - Identifiers use `snake_case`. 26 | - Strings use double quotes (`"`). 27 | - Use a trailing comma for multiline array and object literals to minimize diffs. 28 | - The Uglify code only uses ES5, even in the `harmony` branch. 29 | - Line length should be at most 80 cols, except when it is easier to read a 30 | longer line. 31 | - If both sides of a comparison are of the same type, `==` and `!=` are used. 32 | - Multiline conditions place `&&` and `||` first on the line. 33 | 34 | **Example feature** 35 | 36 | ```js 37 | OPT(AST_Debugger, function(self, compressor) { 38 | if (compressor.option("drop_debugger")) 39 | return make_node(AST_EmptyStatement, self); 40 | return self; 41 | }); 42 | ``` 43 | 44 | **Example test case** 45 | 46 | ```js 47 | drop_debugger: { 48 | options = { 49 | drop_debugger: true, 50 | } 51 | input: { 52 | debugger; 53 | if (foo) debugger; 54 | } 55 | expect: { 56 | if (foo); 57 | } 58 | } 59 | ``` 60 | 61 | 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | UglifyJS is released under the BSD license: 2 | 3 | Copyright 2012-2024 (c) Mihai Bazon 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials 16 | provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY 19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 27 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 28 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uglify-js", 3 | "description": "JavaScript parser, mangler/compressor and beautifier toolkit", 4 | "author": "Mihai Bazon (http://lisperator.net/)", 5 | "license": "BSD-2-Clause", 6 | "version": "3.19.3", 7 | "engines": { 8 | "node": ">=0.8.0" 9 | }, 10 | "maintainers": [ 11 | "Alex Lam ", 12 | "Mihai Bazon (http://lisperator.net/)" 13 | ], 14 | "repository": "mishoo/UglifyJS", 15 | "main": "tools/node.js", 16 | "bin": { 17 | "uglifyjs": "bin/uglifyjs" 18 | }, 19 | "files": [ 20 | "bin", 21 | "lib", 22 | "tools", 23 | "LICENSE" 24 | ], 25 | "devDependencies": { 26 | "acorn": "~8.7.1", 27 | "semver": "~6.3.0" 28 | }, 29 | "scripts": { 30 | "test": "node test/compress.js && node test/mocha.js" 31 | }, 32 | "keywords": [ 33 | "cli", 34 | "compress", 35 | "compressor", 36 | "ecma", 37 | "ecmascript", 38 | "es", 39 | "es5", 40 | "javascript", 41 | "js", 42 | "jsmin", 43 | "min", 44 | "minification", 45 | "minifier", 46 | "minify", 47 | "optimize", 48 | "optimizer", 49 | "pack", 50 | "packer", 51 | "parse", 52 | "parser", 53 | "uglifier", 54 | "uglify" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /test/benchmark.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | // -*- js -*- 3 | 4 | "use strict"; 5 | 6 | require("../tools/tty"); 7 | var createHash = require("crypto").createHash; 8 | var fetch = require("./fetch"); 9 | var spawn = require("child_process").spawn; 10 | var zlib = require("zlib"); 11 | var args = process.argv.slice(2); 12 | if (!args.length) args.push("-mc"); 13 | args.unshift("bin/uglifyjs"); 14 | args.push("--timings"); 15 | var urls = [ 16 | "https://code.jquery.com/jquery-3.4.1.js", 17 | "https://code.angularjs.org/1.7.8/angular.js", 18 | "https://unpkg.com/mathjs@6.2.3/dist/math.js", 19 | "https://unpkg.com/react@15.3.2/dist/react.js", 20 | "https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.js", 21 | "https://cdnjs.cloudflare.com/ajax/libs/antd/4.18.7/antd.js", 22 | "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js", 23 | "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js", 24 | "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.12.2/ember.prod.js", 25 | "https://raw.githubusercontent.com/kangax/html-minifier/v4.0.0/dist/htmlminifier.js", 26 | ]; 27 | var results = {}; 28 | var remaining = 2 * urls.length; 29 | function done() { 30 | if (!--remaining) { 31 | var failures = []; 32 | var sum = { input: 0, output: 0, gzip: 0 }; 33 | urls.forEach(function(url) { 34 | var info = results[url]; 35 | console.log(); 36 | console.log(url); 37 | console.log(info.log); 38 | console.log("Original:", info.input, "bytes"); 39 | console.log("Uglified:", info.output, "bytes"); 40 | console.log("GZipped: ", info.gzip, "bytes"); 41 | console.log("SHA1 sum:", info.sha1); 42 | if (info.code) { 43 | failures.push(url); 44 | } 45 | sum.input += info.input; 46 | sum.output += info.output; 47 | sum.gzip += info.gzip; 48 | }); 49 | if (failures.length) { 50 | console.error("Benchmark failed:"); 51 | failures.forEach(function(url) { 52 | console.error(url); 53 | }); 54 | process.exit(1); 55 | } else { 56 | console.log(); 57 | console.log("Subtotal"); 58 | console.log(); 59 | console.log("Original:", sum.input, "bytes"); 60 | console.log("Uglified:", sum.output, "bytes"); 61 | console.log("GZipped: ", sum.gzip, "bytes"); 62 | } 63 | } 64 | } 65 | urls.forEach(function(url) { 66 | results[url] = { 67 | input: 0, 68 | output: 0, 69 | gzip: 0, 70 | log: "" 71 | }; 72 | fetch(url, function(err, res) { 73 | if (err) throw err; 74 | var uglifyjs = spawn(process.argv[0], args, { silent: true }); 75 | res.on("data", function(data) { 76 | results[url].input += data.length; 77 | }).pipe(uglifyjs.stdin); 78 | var sha1 = createHash("sha1"); 79 | uglifyjs.stdout.on("data", function(data) { 80 | results[url].output += data.length; 81 | }).pipe(zlib.createGzip({ 82 | level: zlib.Z_BEST_COMPRESSION 83 | })).on("data", function(data) { 84 | results[url].gzip += data.length; 85 | sha1.update(data); 86 | }).on("end", function() { 87 | results[url].sha1 = sha1.digest("hex"); 88 | done(); 89 | }); 90 | uglifyjs.stderr.setEncoding("utf8"); 91 | uglifyjs.stderr.on("data", function(data) { 92 | results[url].log += data; 93 | }); 94 | uglifyjs.on("exit", function(code) { 95 | results[url].code = code; 96 | done(); 97 | }); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /test/compress/bigint.js: -------------------------------------------------------------------------------- 1 | arithmetic: { 2 | input: { 3 | console.log(((1n + 0x2n) * (0o3n - -4n)) >> (5n - 6n)); 4 | } 5 | expect_exact: "console.log((1n+0x2n)*(0o3n- -4n)>>5n-6n);" 6 | expect_stdout: "42n" 7 | node_version: ">=10.4.0" 8 | } 9 | 10 | minus_dot: { 11 | input: { 12 | console.log(typeof -42n.toString(), typeof (-42n).toString()); 13 | } 14 | expect_exact: "console.log(typeof-42n.toString(),typeof(-42n).toString());" 15 | expect_stdout: "number string" 16 | node_version: ">=10.4.0" 17 | } 18 | 19 | evaluate: { 20 | options = { 21 | evaluate: true, 22 | unsafe: true, 23 | } 24 | input: { 25 | console.log((0xDEAD_BEEFn).toString(16)); 26 | } 27 | expect: { 28 | console.log(0xdeadbeefn.toString(16)); 29 | } 30 | expect_stdout: "deadbeef" 31 | node_version: ">=10.4.0" 32 | } 33 | 34 | Number: { 35 | options = { 36 | unsafe: true, 37 | } 38 | input: { 39 | console.log(Number(-0xfeed_dead_beef_badn)); 40 | } 41 | expect: { 42 | console.log(+("" + -0xfeed_dead_beef_badn)); 43 | } 44 | expect_stdout: "-1148098955808013200" 45 | node_version: ">=10.4.0" 46 | } 47 | 48 | issue_4590: { 49 | options = { 50 | collapse_vars: true, 51 | } 52 | input: { 53 | A = 1; 54 | 0n || console.log("PASS"); 55 | } 56 | expect: { 57 | A = 1; 58 | 0n || console.log("PASS"); 59 | } 60 | expect_stdout: "PASS" 61 | node_version: ">=10.4.0" 62 | } 63 | 64 | issue_4801: { 65 | options = { 66 | booleans: true, 67 | collapse_vars: true, 68 | reduce_vars: true, 69 | unused: true, 70 | } 71 | input: { 72 | try { 73 | (function(a) { 74 | A = 42; 75 | a || A; 76 | })(!(0 == 42 >> 0o644n)); 77 | } catch (e) { 78 | console.log("PASS"); 79 | } 80 | } 81 | expect: { 82 | try { 83 | (function(a) { 84 | 0 != (A = 42) >> 0o644n || A; 85 | })(); 86 | } catch (e) { 87 | console.log("PASS"); 88 | } 89 | } 90 | expect_stdout: "PASS" 91 | node_version: ">=10.4.0" 92 | } 93 | 94 | issue_5728: { 95 | options = { 96 | evaluate: true, 97 | } 98 | input: { 99 | console.log("" + 4n + 2); 100 | } 101 | expect: { 102 | console.log("42"); 103 | } 104 | expect_stdout: "42" 105 | node_version: ">=10.4.0" 106 | } 107 | -------------------------------------------------------------------------------- /test/compress/blocks.js: -------------------------------------------------------------------------------- 1 | remove_blocks: { 2 | input: { 3 | {;} 4 | foo(); 5 | {}; 6 | { 7 | {}; 8 | }; 9 | bar(); 10 | {} 11 | } 12 | expect: { 13 | foo(); 14 | bar(); 15 | } 16 | } 17 | 18 | keep_some_blocks: { 19 | input: { 20 | // 1. 21 | if (foo) { 22 | {{{}}} 23 | if (bar) { baz(); } 24 | {{}} 25 | } else { 26 | stuff(); 27 | } 28 | 29 | // 2. 30 | if (foo) { 31 | for (var i = 0; i < 5; ++i) 32 | if (bar) baz(); 33 | } else { 34 | stuff(); 35 | } 36 | } 37 | expect: { 38 | // 1. 39 | if (foo) { 40 | if (bar) baz(); 41 | } else stuff(); 42 | 43 | // 2. 44 | if (foo) { 45 | for (var i = 0; i < 5; ++i) 46 | if (bar) baz(); 47 | } else stuff(); 48 | } 49 | } 50 | 51 | issue_1666: { 52 | input: { 53 | var a = 42; 54 | { 55 | function a() {} 56 | a(); 57 | } 58 | console.log("PASS"); 59 | } 60 | expect: { 61 | var a = 42; 62 | { 63 | function a() {} 64 | a(); 65 | } 66 | console.log("PASS"); 67 | } 68 | expect_stdout: true 69 | } 70 | 71 | issue_1666_strict: { 72 | input: { 73 | "use strict"; 74 | var a = 42; 75 | { 76 | function a() {} 77 | a(); 78 | } 79 | console.log("PASS"); 80 | } 81 | expect: { 82 | "use strict"; 83 | var a = 42; 84 | { 85 | function a() {} 86 | a(); 87 | } 88 | console.log("PASS"); 89 | } 90 | expect_stdout: true 91 | } 92 | -------------------------------------------------------------------------------- /test/compress/debugger.js: -------------------------------------------------------------------------------- 1 | keep_debugger: { 2 | options = { 3 | drop_debugger: false, 4 | } 5 | input: { 6 | debugger; 7 | } 8 | expect: { 9 | debugger; 10 | } 11 | } 12 | 13 | drop_debugger: { 14 | options = { 15 | drop_debugger: true, 16 | } 17 | input: { 18 | debugger; 19 | if (foo) debugger; 20 | } 21 | expect: { 22 | if (foo); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/compress/directives.js: -------------------------------------------------------------------------------- 1 | simple_statement_is_not_a_directive: { 2 | input: { 3 | "use strict" 4 | .split(" ") 5 | .forEach(function(s) { 6 | console.log(s); 7 | }); 8 | console.log(!this); // is strict mode? 9 | (function() { 10 | "directive" 11 | "" 12 | "use strict" 13 | "hello world" 14 | .split(" ") 15 | .forEach(function(s) { 16 | console.log(s); 17 | }); 18 | console.log(!this); // is strict mode? 19 | })(); 20 | } 21 | expect: { 22 | "use strict".split(" ").forEach(function(s) { 23 | console.log(s); 24 | }); 25 | console.log(!this); 26 | (function() { 27 | "directive"; 28 | ""; 29 | "use strict"; 30 | "hello world".split(" ").forEach(function(s) { 31 | console.log(s); 32 | }); 33 | console.log(!this); 34 | })(); 35 | } 36 | expect_stdout: [ 37 | "use", 38 | "strict", 39 | "false", 40 | "hello", 41 | "world", 42 | "true", 43 | ] 44 | } 45 | 46 | drop_lone_use_strict: { 47 | options = { 48 | directives: true, 49 | unused: true, 50 | } 51 | input: { 52 | function f1() { 53 | "use strict"; 54 | } 55 | function f2() { 56 | "use strict"; 57 | function f3() { 58 | "use strict"; 59 | } 60 | } 61 | (function f4() { 62 | "use strict"; 63 | })(); 64 | } 65 | expect: { 66 | function f1() { 67 | } 68 | function f2() { 69 | } 70 | (function() {})(); 71 | } 72 | } 73 | 74 | issue_3166: { 75 | options = { 76 | directives: true, 77 | } 78 | input: { 79 | "foo"; 80 | "use strict"; 81 | function f() { 82 | "use strict"; 83 | "bar"; 84 | "use asm"; 85 | } 86 | } 87 | expect: { 88 | "use strict"; 89 | function f() { 90 | "use asm"; 91 | } 92 | } 93 | } 94 | 95 | valid_after_invalid_1: { 96 | input: { 97 | console.log(typeof function() { 98 | "use\x20strict"; 99 | "use strict"; 100 | return this; 101 | }()); 102 | } 103 | expect: { 104 | console.log(typeof function() { 105 | "use\x20strict"; 106 | "use strict"; 107 | return this; 108 | }()); 109 | } 110 | expect_stdout: "undefined" 111 | } 112 | 113 | valid_after_invalid_2: { 114 | options = { 115 | directives: true, 116 | } 117 | input: { 118 | console.log(typeof function() { 119 | "use\x20strict"; 120 | "use strict"; 121 | return this; 122 | }()); 123 | } 124 | expect: { 125 | console.log(typeof function() { 126 | "use strict"; 127 | return this; 128 | }()); 129 | } 130 | expect_stdout: "undefined" 131 | } 132 | 133 | issue_5368_1: { 134 | expression = true 135 | options = { 136 | directives: true, 137 | expression: true, 138 | } 139 | input: { 140 | "foo" 141 | } 142 | expect_exact: '"foo"' 143 | expect_stdout: "foo" 144 | } 145 | 146 | issue_5368_2: { 147 | expression = true 148 | options = { 149 | directives: true, 150 | expression: true, 151 | } 152 | input: { 153 | (function() { 154 | "foo"; 155 | })() 156 | } 157 | expect_exact: "function(){}()" 158 | expect_stdout: "undefined" 159 | } 160 | 161 | issue_5368_3: { 162 | options = { 163 | directives: true, 164 | expression: true, 165 | } 166 | input: { 167 | "foo"; 168 | (function() { 169 | "bar"; 170 | })(); 171 | } 172 | expect: { 173 | (function() {})(); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /test/compress/drop-console.js: -------------------------------------------------------------------------------- 1 | drop_console_1: { 2 | options = {} 3 | input: { 4 | console.log('foo'); 5 | console.log.apply(console, arguments); 6 | } 7 | expect: { 8 | console.log('foo'); 9 | console.log.apply(console, arguments); 10 | } 11 | } 12 | 13 | drop_console_2: { 14 | options = { 15 | drop_console: true, 16 | } 17 | input: { 18 | console.log('foo'); 19 | console.log.apply(console, arguments); 20 | } 21 | expect: { 22 | // with regular compression these will be stripped out as well 23 | void 0; 24 | void 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/compress/exponentiation.js: -------------------------------------------------------------------------------- 1 | precedence_1: { 2 | input: { 3 | console.log(-4 ** 3 ** 2); 4 | } 5 | expect_exact: "console.log((-4)**3**2);" 6 | expect_stdout: "-262144" 7 | node_version: ">=8" 8 | } 9 | 10 | precedence_2: { 11 | input: { 12 | console.log(-4 ** (3 ** 2)); 13 | } 14 | expect_exact: "console.log((-4)**3**2);" 15 | expect_stdout: "-262144" 16 | node_version: ">=8" 17 | } 18 | 19 | precedence_3: { 20 | input: { 21 | console.log(-(4 ** 3) ** 2); 22 | } 23 | expect_exact: "console.log((-(4**3))**2);" 24 | expect_stdout: "4096" 25 | node_version: ">=8" 26 | } 27 | 28 | precedence_4: { 29 | input: { 30 | console.log((-4 ** 3) ** 2); 31 | } 32 | expect_exact: "console.log(((-4)**3)**2);" 33 | expect_stdout: "4096" 34 | node_version: ">=8" 35 | } 36 | 37 | await: { 38 | input: { 39 | (async a => a * await a ** ++a % a)(2).then(console.log); 40 | } 41 | expect_exact: "(async a=>a*(await a)**++a%a)(2).then(console.log);" 42 | expect_stdout: "1" 43 | node_version: ">=8" 44 | } 45 | 46 | assignment_1: { 47 | input: { 48 | var a = 2; 49 | a **= 5; 50 | console.log(a); 51 | } 52 | expect_exact: "var a=2;a**=5;console.log(a);" 53 | expect_stdout: "32" 54 | node_version: ">=8" 55 | } 56 | 57 | assignment_2: { 58 | input: { 59 | var a = 8n; 60 | a **= a; 61 | console.log(a); 62 | } 63 | expect_exact: "var a=8n;a**=a;console.log(a);" 64 | expect_stdout: "16777216n" 65 | node_version: ">=10.4.0" 66 | } 67 | 68 | evaluate: { 69 | options = { 70 | evaluate: true, 71 | } 72 | input: { 73 | console.log(1 + 2 ** 3 - 4); 74 | } 75 | expect: { 76 | console.log(5); 77 | } 78 | expect_stdout: "5" 79 | node_version: ">=8" 80 | } 81 | 82 | issue_4664: { 83 | options = { 84 | collapse_vars: true, 85 | evaluate: true, 86 | reduce_vars: true, 87 | side_effects: true, 88 | toplevel: true, 89 | unused: true, 90 | } 91 | input: { 92 | function f() { 93 | new function(a) { 94 | console.log(typeof f, a, typeof this); 95 | }((A = 0, (NaN ^ 1) * 2 ** 30), 0); 96 | } 97 | f(); 98 | } 99 | expect: { 100 | (function f() { 101 | new function(a) { 102 | console.log(typeof f, 2 ** 30, typeof this); 103 | }(A = 0); 104 | })(); 105 | } 106 | expect_stdout: "function 1073741824 object" 107 | node_version: ">=8" 108 | } 109 | 110 | issue_4715: { 111 | options = { 112 | evaluate: true, 113 | } 114 | input: { 115 | A = 1; 116 | console.log((-0) ** A + 0); 117 | console.log((-0) ** A - 0); 118 | console.log((-0) ** A * 1); 119 | console.log((-0) ** A / 1); 120 | console.log(Math.pow(-0, A) + 0); 121 | console.log(Math.pow(-0, A) - 0); 122 | console.log(Math.pow(-0, A) * 1); 123 | console.log(Math.pow(-0, A) / 1); 124 | } 125 | expect: { 126 | A = 1; 127 | console.log((-0) ** A + 0); 128 | console.log((-0) ** A); 129 | console.log((-0) ** A * 1); 130 | console.log((-0) ** A); 131 | console.log(Math.pow(-0, A) + 0); 132 | console.log(+Math.pow(-0, A)); 133 | console.log(+Math.pow(-0, A)); 134 | console.log(+Math.pow(-0, A)); 135 | } 136 | expect_stdout: [ 137 | "0", 138 | "-0", 139 | "-0", 140 | "-0", 141 | "0", 142 | "-0", 143 | "-0", 144 | "-0", 145 | ] 146 | node_version: ">=8" 147 | } 148 | -------------------------------------------------------------------------------- /test/compress/html_comments.js: -------------------------------------------------------------------------------- 1 | html_comment_in_expression: { 2 | input: { 3 | (function(a, b) { 4 | console.log(a < !--b && a-- > b, a, b); 5 | })(1, 2); 6 | } 7 | expect_exact: "(function(a,b){console.log(ab,a,b)})(1,2);" 8 | expect_stdout: "false 1 1" 9 | } 10 | 11 | html_comment_in_less_than: { 12 | input: { 13 | (function(a, b, c) { 14 | console.log( 15 | a < !--b, 16 | a < !--b + c, 17 | a + b < !--c, 18 | a, b, c 19 | ); 20 | })(1, 2, 3); 21 | } 22 | expect_exact: "(function(a,b,c){console.log(a b, 46 | a-- > b + c, 47 | a + b-- > c, 48 | a, b, c 49 | ); 50 | })(1, 2, 3); 51 | } 52 | expect_exact: "(function(a,b,c){console.log(a-- >b,a-- >b+c,a+b-- >c,a,b,c)})(1,2,3);" 53 | expect_stdout: "false false false -1 1 3" 54 | } 55 | 56 | html_comment_in_greater_than_or_equal: { 57 | input: { 58 | (function(a, b, c) { 59 | console.log( 60 | a-- >= b, 61 | a-- >= b + c, 62 | a + b-- >= c, 63 | a, b, c 64 | ); 65 | })(1, 2, 3); 66 | } 67 | expect_exact: "(function(a,b,c){console.log(a-- >=b,a-- >=b+c,a+b-- >=c,a,b,c)})(1,2,3);" 68 | expect_stdout: "false false false -1 1 3" 69 | } 70 | 71 | html_comment_in_right_shift: { 72 | input: { 73 | (function(a, b, c) { 74 | console.log( 75 | a-- >> b, 76 | a-- >> b + c, 77 | a + b-- >> c, 78 | a, b, c 79 | ); 80 | })(1, 2, 3); 81 | } 82 | expect_exact: "(function(a,b,c){console.log(a-- >>b,a-- >>b+c,a+b-- >>c,a,b,c)})(1,2,3);" 83 | expect_stdout: "0 0 0 -1 1 3" 84 | } 85 | 86 | html_comment_in_zero_fill_right_shift: { 87 | input: { 88 | (function(a, b, c) { 89 | console.log( 90 | a-- >>> b, 91 | a-- >>> b + c, 92 | a + b-- >>> c, 93 | a, b, c 94 | ); 95 | })(1, 2, 3); 96 | } 97 | expect_exact: "(function(a,b,c){console.log(a-- >>>b,a-- >>>b+c,a+b-- >>>c,a,b,c)})(1,2,3);" 98 | expect_stdout: "0 0 0 -1 1 3" 99 | } 100 | 101 | html_comment_in_string_literal: { 102 | input: { 103 | console.log("comment in".length); 104 | } 105 | expect_exact: 'console.log("\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e".length);' 106 | expect_stdout: "42" 107 | } 108 | -------------------------------------------------------------------------------- /test/compress/indentation.js: -------------------------------------------------------------------------------- 1 | numeric: { 2 | beautify = { 3 | beautify: true, 4 | indent_start: 1, 5 | indent_level: 3, 6 | } 7 | input: { 8 | switch (42) { 9 | case null: 10 | console.log("FAIL"); 11 | } 12 | console.log("PASS"); 13 | } 14 | expect_exact: [ 15 | " switch (42) {", 16 | " case null:", 17 | ' console.log("FAIL");', 18 | " }", 19 | "", 20 | ' console.log("PASS");', 21 | ] 22 | expect_stdout: "PASS" 23 | } 24 | 25 | spaces: { 26 | beautify = { 27 | beautify: true, 28 | indent_start: " ", 29 | indent_level: " ", 30 | } 31 | input: { 32 | switch (42) { 33 | case null: 34 | console.log("FAIL"); 35 | } 36 | console.log("PASS"); 37 | } 38 | expect_exact: [ 39 | " switch (42) {", 40 | " case null:", 41 | ' console.log("FAIL");', 42 | " }", 43 | "", 44 | ' console.log("PASS");', 45 | ] 46 | expect_stdout: "PASS" 47 | } 48 | 49 | tabs: { 50 | beautify = { 51 | beautify: true, 52 | indent_start: "\t", 53 | indent_level: "\t", 54 | } 55 | input: { 56 | switch (42) { 57 | case null: 58 | console.log("FAIL"); 59 | } 60 | console.log("PASS"); 61 | } 62 | expect_exact: [ 63 | "\tswitch (42) {", 64 | "\tcase null:", 65 | '\t\tconsole.log("FAIL");', 66 | "\t}", 67 | "", 68 | '\tconsole.log("PASS");', 69 | ] 70 | expect_stdout: "PASS" 71 | } 72 | 73 | mixed: { 74 | beautify = { 75 | beautify: true, 76 | indent_start: "\n", 77 | indent_level: " \t", 78 | } 79 | input: { 80 | switch (42) { 81 | case null: 82 | console.log("FAIL"); 83 | } 84 | console.log("PASS"); 85 | } 86 | expect_exact: [ 87 | "", 88 | "switch (42) {", 89 | "", 90 | " case null:", 91 | "", 92 | ' \tconsole.log("FAIL");', 93 | "", 94 | "}", 95 | "", 96 | "", 97 | 'console.log("PASS");', 98 | ] 99 | expect_stdout: "PASS" 100 | } 101 | -------------------------------------------------------------------------------- /test/compress/issue-1041.js: -------------------------------------------------------------------------------- 1 | const_pragma: { 2 | options = { 3 | evaluate: true, 4 | reduce_funcs: true, 5 | reduce_vars: true, 6 | } 7 | 8 | input: { 9 | /** @const */ var goog = goog || {}; 10 | } 11 | expect: { 12 | var goog = goog || {}; 13 | } 14 | } 15 | 16 | // for completeness' sake 17 | not_const: { 18 | options = { 19 | evaluate: true, 20 | reduce_funcs: true, 21 | reduce_vars: true, 22 | } 23 | 24 | input: { 25 | var goog = goog || {}; 26 | } 27 | expect: { 28 | var goog = goog || {}; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/compress/issue-1052.js: -------------------------------------------------------------------------------- 1 | multiple_functions: { 2 | options = { 3 | hoist_funs: false, 4 | if_return: true, 5 | } 6 | input: { 7 | (function() { 8 | if (!window) 9 | return; 10 | function f() {} 11 | function g() {} 12 | })(); 13 | } 14 | expect: { 15 | (function() { 16 | // NOTE: other compression steps will reduce this 17 | // down to just `window`. 18 | if (!window); 19 | function f() {} 20 | function g() {} 21 | })(); 22 | } 23 | } 24 | 25 | single_function: { 26 | options = { 27 | hoist_funs: false, 28 | if_return: true, 29 | } 30 | input: { 31 | (function() { 32 | if (!window) 33 | return; 34 | function f() {} 35 | })(); 36 | } 37 | expect: { 38 | (function() { 39 | if (!window); 40 | function f() {} 41 | })(); 42 | } 43 | } 44 | 45 | deeply_nested: { 46 | options = { 47 | hoist_funs: false, 48 | if_return: true, 49 | } 50 | input: { 51 | (function() { 52 | if (!window) 53 | return; 54 | function f() {} 55 | function g() {} 56 | if (!document) 57 | return; 58 | function h() {} 59 | })(); 60 | } 61 | expect: { 62 | (function() { 63 | // NOTE: other compression steps will reduce this 64 | // down to just `window`. 65 | if (!window); 66 | else if (!document); 67 | function f() {} 68 | function g() {} 69 | function h() {} 70 | })(); 71 | } 72 | } 73 | 74 | not_hoisted_when_already_nested: { 75 | options = { 76 | hoist_funs: false, 77 | if_return: true, 78 | } 79 | input: { 80 | (function() { 81 | if (!window) 82 | return; 83 | if (foo) function f() {} 84 | })(); 85 | } 86 | expect: { 87 | (function() { 88 | if (!window); 89 | else if (foo) 90 | function f() {} 91 | })(); 92 | } 93 | } 94 | 95 | defun_if_return: { 96 | options = { 97 | hoist_funs: false, 98 | if_return: true, 99 | } 100 | input: { 101 | function e() { 102 | function f() {} 103 | if (!window) 104 | return; 105 | else 106 | function g() {} 107 | function h() {} 108 | } 109 | } 110 | expect: { 111 | function e() { 112 | function f() {} 113 | if (!window); 114 | else 115 | function g() {} 116 | function h() {} 117 | } 118 | } 119 | } 120 | 121 | defun_hoist_funs: { 122 | options = { 123 | hoist_funs: true, 124 | if_return: true, 125 | } 126 | input: { 127 | function e() { 128 | function f() {} 129 | if (!window) 130 | return; 131 | else 132 | function g() {} 133 | function h() {} 134 | } 135 | } 136 | expect: { 137 | function e() { 138 | function f() {} 139 | function g() {} 140 | function h() {} 141 | if (!window); 142 | } 143 | } 144 | } 145 | 146 | defun_else_if_return: { 147 | options = { 148 | hoist_funs: false, 149 | if_return: true, 150 | } 151 | input: { 152 | function e() { 153 | function f() {} 154 | if (window) 155 | function g() {} 156 | else 157 | return; 158 | function h() {} 159 | } 160 | } 161 | expect: { 162 | function e() { 163 | function f() {} 164 | if (window) 165 | function g() {} 166 | function h() {} 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /test/compress/issue-12.js: -------------------------------------------------------------------------------- 1 | keep_name_of_getter: { 2 | options = { 3 | unused: true, 4 | } 5 | input: { 6 | a = { 7 | get foo() {}, 8 | }; 9 | } 10 | expect: { 11 | a = { 12 | get foo() {}, 13 | }; 14 | } 15 | } 16 | 17 | keep_name_of_setter: { 18 | options = { 19 | unused: true, 20 | } 21 | input: { 22 | a = { 23 | set foo(v) {}, 24 | }; 25 | } 26 | expect: { 27 | a = { 28 | set foo(v) {}, 29 | }; 30 | } 31 | } 32 | 33 | setter_with_operator_keys: { 34 | input: { 35 | var tokenCodes = { 36 | get instanceof() { 37 | return test0; 38 | }, 39 | set instanceof(value) { 40 | test0 = value; 41 | }, 42 | set typeof(value) { 43 | test1 = value; 44 | }, 45 | get typeof() { 46 | return test1; 47 | }, 48 | set else(value) { 49 | test2 = value; 50 | }, 51 | get else() { 52 | return test2; 53 | }, 54 | }; 55 | } 56 | expect: { 57 | var tokenCodes = { 58 | get instanceof() { 59 | return test0; 60 | }, 61 | set instanceof(value) { 62 | test0 = value; 63 | }, 64 | set typeof(value) { 65 | test1 = value; 66 | }, 67 | get typeof() { 68 | return test1; 69 | }, 70 | set else(value) { 71 | test2 = value; 72 | }, 73 | get else() { 74 | return test2; 75 | }, 76 | }; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/compress/issue-1202.js: -------------------------------------------------------------------------------- 1 | mangle_keep_fnames_false: { 2 | options = { 3 | keep_fargs: true, 4 | keep_fnames: true, 5 | } 6 | mangle = { 7 | keep_fnames: false, 8 | } 9 | input: { 10 | "use strict"; 11 | function total() { 12 | return function n(a, b, c) { 13 | return a + b + c; 14 | }; 15 | } 16 | } 17 | expect: { 18 | "use strict"; 19 | function total() { 20 | return function t(n, r, u) { 21 | return n + r + u; 22 | }; 23 | } 24 | } 25 | } 26 | 27 | mangle_keep_fnames_true: { 28 | options = { 29 | keep_fargs: true, 30 | keep_fnames: true, 31 | } 32 | mangle = { 33 | keep_fnames: true, 34 | } 35 | input: { 36 | "use strict"; 37 | function total() { 38 | return function n(a, b, c) { 39 | return a + b + c; 40 | }; 41 | } 42 | } 43 | expect: { 44 | "use strict"; 45 | function total() { 46 | return function n(t, r, u) { 47 | return t + r + u; 48 | }; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/compress/issue-126.js: -------------------------------------------------------------------------------- 1 | concatenate_rhs_strings: { 2 | options = { 3 | evaluate: true, 4 | unsafe: true, 5 | } 6 | input: { 7 | foo(bar() + 123 + "Hello" + "World"); 8 | foo(bar() + (123 + "Hello") + "World"); 9 | foo((bar() + 123) + "Hello" + "World"); 10 | foo(bar() + 123 + "Hello" + "World" + ("Foo" + "Bar")); 11 | foo("Foo" + "Bar" + bar() + 123 + "Hello" + "World" + ("Foo" + "Bar")); 12 | foo("Hello" + bar() + 123 + "World"); 13 | foo(bar() + 'Foo' + (10 + parseInt('10'))); 14 | } 15 | expect: { 16 | foo(bar() + 123 + "HelloWorld"); 17 | foo(bar() + "123HelloWorld"); 18 | foo((bar() + 123) + "HelloWorld"); 19 | foo(bar() + 123 + "HelloWorldFooBar"); 20 | foo("FooBar" + bar() + "123HelloWorldFooBar"); 21 | foo("Hello" + bar() + "123World"); 22 | foo(bar() + 'Foo' + (10 + parseInt('10'))); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/compress/issue-1275.js: -------------------------------------------------------------------------------- 1 | string_plus_optimization: { 2 | options = { 3 | booleans: true, 4 | comparisons: true, 5 | conditionals: true, 6 | dead_code: true, 7 | evaluate: true, 8 | hoist_funs: true, 9 | if_return: true, 10 | join_vars: true, 11 | side_effects: true, 12 | unused: true, 13 | } 14 | input: { 15 | function foo(anything) { 16 | function throwing_function() { 17 | throw "nope"; 18 | } 19 | try { 20 | console.log('0' + throwing_function() ? "yes" : "no"); 21 | } catch (ex) { 22 | console.log(ex); 23 | } 24 | console.log('0' + anything ? "yes" : "no"); 25 | console.log(anything + '0' ? "Yes" : "No"); 26 | console.log('' + anything); 27 | console.log(anything + ''); 28 | } 29 | foo(); 30 | } 31 | expect: { 32 | function foo(anything) { 33 | function throwing_function() { 34 | throw "nope"; 35 | } 36 | try { 37 | console.log((throwing_function(), "yes")); 38 | } catch (ex) { 39 | console.log(ex); 40 | } 41 | console.log("yes"); 42 | console.log("Yes"); 43 | console.log('' + anything); 44 | console.log(anything + ''); 45 | } 46 | foo(); 47 | } 48 | expect_stdout: true 49 | } 50 | -------------------------------------------------------------------------------- /test/compress/issue-1321.js: -------------------------------------------------------------------------------- 1 | issue_1321_no_debug: { 2 | mangle = { 3 | properties: { 4 | domprops: true, 5 | keep_quoted: true, 6 | }, 7 | } 8 | input: { 9 | var x = {}; 10 | x.foo = 1; 11 | x["a"] = 2 * x.foo; 12 | console.log(x.foo, x["a"]); 13 | } 14 | expect: { 15 | var x = {}; 16 | x.x = 1; 17 | x["a"] = 2 * x.x; 18 | console.log(x.x, x["a"]); 19 | } 20 | expect_stdout: true 21 | } 22 | 23 | issue_1321_debug: { 24 | mangle = { 25 | properties: { 26 | debug: "", 27 | domprops: true, 28 | keep_quoted: true, 29 | }, 30 | } 31 | input: { 32 | var x = {}; 33 | x.foo = 1; 34 | x["_$foo$_"] = 2 * x.foo; 35 | console.log(x.foo, x["_$foo$_"]); 36 | } 37 | expect: { 38 | var x = {}; 39 | x.x = 1; 40 | x["_$foo$_"] = 2 * x.x; 41 | console.log(x.x, x["_$foo$_"]); 42 | } 43 | expect_stdout: true 44 | } 45 | 46 | issue_1321_with_quoted: { 47 | mangle = { 48 | properties: { 49 | domprops: true, 50 | keep_quoted: false, 51 | }, 52 | } 53 | input: { 54 | var x = {}; 55 | x.foo = 1; 56 | x["a"] = 2 * x.foo; 57 | console.log(x.foo, x["a"]); 58 | } 59 | expect: { 60 | var x = {}; 61 | x.x = 1; 62 | x["o"] = 2 * x.x; 63 | console.log(x.x, x["o"]); 64 | } 65 | expect_stdout: true 66 | } 67 | -------------------------------------------------------------------------------- /test/compress/issue-143.js: -------------------------------------------------------------------------------- 1 | /** 2 | * There was an incorrect sort behavior documented in issue #143: 3 | * (x = f(…)) <= x → x >= (x = f(…)) 4 | * 5 | * For example, let the equation be: 6 | * (a = parseInt('100')) <= a 7 | * 8 | * If a was an integer and has the value of 99, 9 | * (a = parseInt('100')) <= a → 100 <= 100 → true 10 | * 11 | * When transformed incorrectly: 12 | * a >= (a = parseInt('100')) → 99 >= 100 → false 13 | */ 14 | 15 | transformation_sort_order_equal: { 16 | options = { 17 | comparisons: true, 18 | } 19 | input: { 20 | console.log((a = parseInt("100")) == a); 21 | } 22 | expect: { 23 | console.log((a = parseInt("100")) == a); 24 | } 25 | expect_stdout: "true" 26 | } 27 | 28 | transformation_sort_order_unequal: { 29 | options = { 30 | comparisons: true, 31 | } 32 | input: { 33 | console.log((a = parseInt("100")) != a); 34 | } 35 | expect: { 36 | console.log((a = parseInt("100")) != a); 37 | } 38 | expect_stdout: "false" 39 | } 40 | 41 | transformation_sort_order_lesser_or_equal: { 42 | options = { 43 | comparisons: true, 44 | } 45 | input: { 46 | console.log((a = parseInt("100")) <= a); 47 | } 48 | expect: { 49 | console.log((a = parseInt("100")) <= a); 50 | } 51 | expect_stdout: "true" 52 | } 53 | 54 | transformation_sort_order_greater_or_equal: { 55 | options = { 56 | comparisons: true, 57 | } 58 | input: { 59 | console.log((a = parseInt("100")) >= a); 60 | } 61 | expect: { 62 | console.log((a = parseInt("100")) >= a); 63 | } 64 | expect_stdout: "true" 65 | } 66 | -------------------------------------------------------------------------------- /test/compress/issue-1431.js: -------------------------------------------------------------------------------- 1 | level_zero: { 2 | options = { 3 | keep_fnames: true, 4 | } 5 | mangle = { 6 | keep_fnames: true 7 | } 8 | input: { 9 | function f(x) { 10 | function n(a) { 11 | return a * a; 12 | } 13 | return function() { 14 | return x; 15 | }; 16 | } 17 | } 18 | expect: { 19 | function f(r) { 20 | function n(n) { 21 | return n * n; 22 | } 23 | return function() { 24 | return r; 25 | }; 26 | } 27 | } 28 | } 29 | 30 | level_one: { 31 | options = { 32 | keep_fnames: true, 33 | } 34 | mangle = { 35 | keep_fnames: true 36 | } 37 | input: { 38 | function f(x) { 39 | return function() { 40 | function n(a) { 41 | return a * a; 42 | } 43 | return x(n); 44 | }; 45 | } 46 | } 47 | expect: { 48 | function f(r) { 49 | return function() { 50 | function n(n) { 51 | return n * n; 52 | } 53 | return r(n); 54 | }; 55 | } 56 | } 57 | } 58 | 59 | level_two: { 60 | options = { 61 | keep_fnames: true, 62 | } 63 | mangle = { 64 | keep_fnames: true 65 | } 66 | input: { 67 | function f(x) { 68 | return function() { 69 | function r(a) { 70 | return a * a; 71 | } 72 | return function() { 73 | function n(a) { 74 | return a * a; 75 | } 76 | return x(n); 77 | }; 78 | }; 79 | } 80 | } 81 | expect: { 82 | function f(t) { 83 | return function() { 84 | function r(n) { 85 | return n * n; 86 | } 87 | return function() { 88 | function n(n) { 89 | return n * n; 90 | } 91 | return t(n); 92 | }; 93 | }; 94 | } 95 | } 96 | } 97 | 98 | level_three: { 99 | options = { 100 | keep_fnames: true, 101 | } 102 | mangle = { 103 | keep_fnames: true 104 | } 105 | input: { 106 | function f(x) { 107 | return function() { 108 | function r(a) { 109 | return a * a; 110 | } 111 | return [ 112 | function() { 113 | function t(a) { 114 | return a * a; 115 | } 116 | return t; 117 | }, 118 | function() { 119 | function n(a) { 120 | return a * a; 121 | } 122 | return x(n); 123 | } 124 | ]; 125 | }; 126 | } 127 | } 128 | expect: { 129 | function f(t) { 130 | return function() { 131 | function r(n) { 132 | return n * n; 133 | } 134 | return [ 135 | function() { 136 | function t(n) { 137 | return n * n; 138 | } 139 | return t; 140 | }, 141 | function() { 142 | function n(n) { 143 | return n * n; 144 | } 145 | return t(n); 146 | } 147 | ]; 148 | }; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /test/compress/issue-1443.js: -------------------------------------------------------------------------------- 1 | // tests assume that variable `undefined` not redefined and has `void 0` as value 2 | 3 | unsafe_undefined: { 4 | options = { 5 | conditionals: true, 6 | if_return: true, 7 | unsafe_undefined: true, 8 | } 9 | mangle = {} 10 | input: { 11 | function f(undefined) { 12 | return function() { 13 | if (a) 14 | return b; 15 | if (c) 16 | return d; 17 | }; 18 | } 19 | } 20 | expect: { 21 | function f(n) { 22 | return function() { 23 | return a ? b : c ? d : n; 24 | }; 25 | } 26 | } 27 | } 28 | 29 | keep_fnames: { 30 | options = { 31 | conditionals: true, 32 | if_return: true, 33 | unsafe_undefined: true, 34 | } 35 | mangle = { 36 | keep_fnames: true 37 | } 38 | input: { 39 | function f(undefined) { 40 | return function() { 41 | function n(a) { 42 | return a * a; 43 | } 44 | if (a) 45 | return b; 46 | if (c) 47 | return d; 48 | }; 49 | } 50 | } 51 | expect: { 52 | function f(r) { 53 | return function() { 54 | function n(n) { 55 | return n * n; 56 | } 57 | return a ? b : c ? d : r; 58 | }; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/compress/issue-1446.js: -------------------------------------------------------------------------------- 1 | typeof_eq_undefined: { 2 | options = { 3 | comparisons: true, 4 | typeofs: true, 5 | } 6 | input: { 7 | var a = typeof b != "undefined"; 8 | b = typeof a != "undefined"; 9 | var c = typeof d.e !== "undefined"; 10 | var f = "undefined" === typeof g; 11 | g = "undefined" === typeof f; 12 | var h = "undefined" == typeof i.j; 13 | } 14 | expect: { 15 | var a = "undefined" != typeof b; 16 | b = void 0 !== a; 17 | var c = void 0 !== d.e; 18 | var f = "undefined" == typeof g; 19 | g = void 0 === f; 20 | var h = void 0 === i.j; 21 | } 22 | } 23 | 24 | typeof_eq_undefined_ie8: { 25 | options = { 26 | comparisons: true, 27 | ie: true, 28 | typeofs: true, 29 | } 30 | input: { 31 | var a = typeof b != "undefined"; 32 | b = typeof a != "undefined"; 33 | var c = typeof d.e !== "undefined"; 34 | var f = "undefined" === typeof g; 35 | g = "undefined" === typeof f; 36 | var h = "undefined" == typeof i.j; 37 | } 38 | expect: { 39 | var a = "undefined" != typeof b; 40 | b = void 0 !== a; 41 | var c = "undefined" != typeof d.e; 42 | var f = "undefined" == typeof g; 43 | g = void 0 === f; 44 | var h = "undefined" == typeof i.j; 45 | } 46 | } 47 | 48 | undefined_redefined: { 49 | options = { 50 | comparisons: true, 51 | typeofs: true, 52 | } 53 | input: { 54 | function f(undefined) { 55 | var n = 1; 56 | return typeof n == "undefined"; 57 | } 58 | } 59 | expect_exact: "function f(undefined){var n=1;return void 0===n}" 60 | } 61 | 62 | undefined_redefined_mangle: { 63 | options = { 64 | comparisons: true, 65 | typeofs: true, 66 | } 67 | mangle = {} 68 | input: { 69 | function f(undefined) { 70 | var n = 1; 71 | return typeof n == "undefined"; 72 | } 73 | } 74 | expect_exact: "function f(n){var r=1;return void 0===r}" 75 | } 76 | -------------------------------------------------------------------------------- /test/compress/issue-1447.js: -------------------------------------------------------------------------------- 1 | else_with_empty_block: { 2 | options = {} 3 | input: { 4 | if (x) 5 | yes(); 6 | else { 7 | } 8 | } 9 | expect_exact: "if(x)yes();" 10 | } 11 | 12 | else_with_empty_statement: { 13 | options = {} 14 | input: { 15 | if (x) 16 | yes(); 17 | else 18 | ; 19 | } 20 | expect_exact: "if(x)yes();" 21 | } 22 | 23 | conditional_false_stray_else_in_loop: { 24 | options = { 25 | booleans: true, 26 | comparisons: true, 27 | conditionals: false, 28 | dead_code: true, 29 | evaluate: true, 30 | hoist_vars: true, 31 | if_return: true, 32 | join_vars: true, 33 | loops: true, 34 | side_effects: true, 35 | unused: true, 36 | } 37 | input: { 38 | for (var i = 1; i <= 4; ++i) { 39 | if (i <= 2) continue; 40 | console.log(i); 41 | } 42 | } 43 | expect_exact: "for(var i=1;i<=4;++i)if(i<=2);else console.log(i);" 44 | expect_stdout: [ 45 | "3", 46 | "4", 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /test/compress/issue-1569.js: -------------------------------------------------------------------------------- 1 | inner_reference: { 2 | options = { 3 | side_effects: true, 4 | } 5 | input: { 6 | !function f(a) { 7 | return a && f(a - 1) + a; 8 | }(42); 9 | !function g(a) { 10 | return a; 11 | }(42); 12 | } 13 | expect: { 14 | !function f(a) { 15 | return a && f(a - 1) + a; 16 | }(42); 17 | !void 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/compress/issue-1588.js: -------------------------------------------------------------------------------- 1 | screw_ie8: { 2 | options = { 3 | ie: false, 4 | } 5 | mangle = { 6 | ie: false, 7 | } 8 | input: { 9 | try { throw "foo"; } catch (x) { console.log(x); } 10 | } 11 | expect_exact: 'try{throw"foo"}catch(o){console.log(o)}' 12 | expect_stdout: [ 13 | "foo" 14 | ] 15 | } 16 | 17 | support_ie8: { 18 | options = { 19 | ie: true, 20 | } 21 | mangle = { 22 | ie: true, 23 | } 24 | input: { 25 | try { throw "foo"; } catch (x) { console.log(x); } 26 | } 27 | expect_exact: 'try{throw"foo"}catch(x){console.log(x)}' 28 | expect_stdout: "foo" 29 | } 30 | 31 | safe_undefined: { 32 | options = { 33 | conditionals: true, 34 | if_return: true, 35 | unsafe: false, 36 | } 37 | mangle = {} 38 | input: { 39 | var a, c; 40 | console.log(function(undefined) { 41 | return function() { 42 | if (a) 43 | return b; 44 | if (c) 45 | return d; 46 | }; 47 | }(1)()); 48 | } 49 | expect: { 50 | var a, c; 51 | console.log(function(n) { 52 | return function() { 53 | return a ? b : c ? d : void 0; 54 | }; 55 | }(1)()); 56 | } 57 | expect_stdout: true 58 | } 59 | 60 | unsafe_undefined: { 61 | options = { 62 | conditionals: true, 63 | if_return: true, 64 | unsafe_undefined: true, 65 | } 66 | mangle = {} 67 | input: { 68 | var a, c; 69 | console.log(function(undefined) { 70 | return function() { 71 | if (a) 72 | return b; 73 | if (c) 74 | return d; 75 | }; 76 | }()()); 77 | } 78 | expect: { 79 | var a, c; 80 | console.log(function(n) { 81 | return function() { 82 | return a ? b : c ? d : n; 83 | }; 84 | }()()); 85 | } 86 | expect_stdout: true 87 | } 88 | -------------------------------------------------------------------------------- /test/compress/issue-1609.js: -------------------------------------------------------------------------------- 1 | chained_evaluation_1: { 2 | options = { 3 | collapse_vars: true, 4 | evaluate: true, 5 | reduce_funcs: true, 6 | reduce_vars: true, 7 | unused: true, 8 | } 9 | input: { 10 | (function() { 11 | var a = 1; 12 | (function() { 13 | var b = a, c; 14 | c = f(b); 15 | c.bar = b; 16 | })(); 17 | })(); 18 | } 19 | expect: { 20 | (function() { 21 | (function() { 22 | f(1).bar = 1; 23 | })(); 24 | })(); 25 | } 26 | } 27 | 28 | chained_evaluation_2: { 29 | options = { 30 | collapse_vars: true, 31 | evaluate: true, 32 | reduce_funcs: true, 33 | reduce_vars: true, 34 | unused: true, 35 | } 36 | input: { 37 | (function() { 38 | var a = "long piece of string"; 39 | (function() { 40 | var b = a, c; 41 | c = f(b); 42 | c.bar = b; 43 | })(); 44 | })(); 45 | } 46 | expect: { 47 | (function() { 48 | (function() { 49 | var b = "long piece of string"; 50 | f(b).bar = b; 51 | })(); 52 | })(); 53 | } 54 | } 55 | 56 | chained_evaluation_3: { 57 | options = { 58 | collapse_vars: true, 59 | evaluate: 10, 60 | reduce_funcs: true, 61 | reduce_vars: true, 62 | unused: true, 63 | } 64 | input: { 65 | (function() { 66 | var a = "long piece of string"; 67 | (function() { 68 | var b = a, c; 69 | c = f(b); 70 | c.bar = b; 71 | })(); 72 | })(); 73 | } 74 | expect: { 75 | (function() { 76 | (function() { 77 | f("long piece of string").bar = "long piece of string"; 78 | })(); 79 | })(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /test/compress/issue-1639.js: -------------------------------------------------------------------------------- 1 | issue_1639_1: { 2 | options = { 3 | booleans: true, 4 | collapse_vars: true, 5 | conditionals: true, 6 | evaluate: true, 7 | join_vars: true, 8 | loops: true, 9 | sequences: true, 10 | side_effects: true, 11 | } 12 | input: { 13 | var a = 100, b = 10; 14 | var L1 = 5; 15 | while (--L1 > 0) { 16 | if ((--b), false) { 17 | if (b) { 18 | var ignore = 0; 19 | } 20 | } 21 | } 22 | console.log(a, b); 23 | } 24 | expect: { 25 | for (var a = 100, b = 10, L1 = 5, ignore; --L1 > 0;) { 26 | --b; 27 | } 28 | console.log(a, b); 29 | } 30 | expect_stdout: "100 6" 31 | } 32 | 33 | issue_1639_2: { 34 | options = { 35 | booleans: true, 36 | collapse_vars: true, 37 | conditionals: true, 38 | evaluate: true, 39 | join_vars: true, 40 | sequences: true, 41 | side_effects: true, 42 | } 43 | input: { 44 | var a = 100, b = 10; 45 | function f19() { 46 | if (++a, false) 47 | if (a) 48 | if (++a); 49 | } 50 | f19(); 51 | console.log(a, b); 52 | } 53 | expect: { 54 | var a = 100, b = 10; 55 | function f19() { 56 | ++a, 1; 57 | } 58 | f19(), 59 | console.log(a, b); 60 | } 61 | expect_stdout: "101 10" 62 | } 63 | 64 | issue_1639_3: { 65 | options = { 66 | booleans: true, 67 | collapse_vars: true, 68 | conditionals: true, 69 | evaluate: true, 70 | sequences: true, 71 | side_effects: true, 72 | } 73 | input: { 74 | var a = 100, b = 10; 75 | a++ && false && a ? 0 : 0; 76 | console.log(a, b); 77 | } 78 | expect: { 79 | var a = 100, b = 10; 80 | a++, 81 | console.log(a, b); 82 | } 83 | expect_stdout: "101 10" 84 | } 85 | -------------------------------------------------------------------------------- /test/compress/issue-1656.js: -------------------------------------------------------------------------------- 1 | f7: { 2 | options = { 3 | booleans: true, 4 | collapse_vars: true, 5 | comparisons: true, 6 | conditionals: true, 7 | dead_code: true, 8 | drop_debugger: true, 9 | evaluate: true, 10 | hoist_funs: true, 11 | if_return: true, 12 | join_vars: true, 13 | loops: true, 14 | negate_iife: true, 15 | passes: 3, 16 | properties: true, 17 | reduce_funcs: true, 18 | reduce_vars: true, 19 | sequences: true, 20 | side_effects: true, 21 | toplevel: true, 22 | unused: true, 23 | } 24 | beautify = { 25 | beautify: true, 26 | } 27 | input: { 28 | var a = 100, b = 10; 29 | function f22464() { 30 | var brake146670 = 5; 31 | while (((b = a) ? !a : ~a ? null : b += a) && --brake146670 > 0) { 32 | } 33 | } 34 | f22464(); 35 | console.log(a, b); 36 | } 37 | expect_exact: [ 38 | "console.log(100, 100);", 39 | ] 40 | expect_stdout: "100 100" 41 | } 42 | -------------------------------------------------------------------------------- /test/compress/issue-1673.js: -------------------------------------------------------------------------------- 1 | side_effects_catch: { 2 | options = { 3 | reduce_funcs: true, 4 | reduce_vars: true, 5 | side_effects: true, 6 | unused: true, 7 | } 8 | input: { 9 | function f() { 10 | function g() { 11 | try { 12 | throw 0; 13 | } catch (e) { 14 | console.log("PASS"); 15 | } 16 | } 17 | g(); 18 | } 19 | f(); 20 | } 21 | expect: { 22 | function f() { 23 | (function() { 24 | try { 25 | throw 0; 26 | } catch (e) { 27 | console.log("PASS"); 28 | } 29 | })(); 30 | } 31 | f(); 32 | } 33 | expect_stdout: "PASS" 34 | } 35 | 36 | side_effects_else: { 37 | options = { 38 | reduce_funcs: true, 39 | reduce_vars: true, 40 | side_effects: true, 41 | unused: true, 42 | } 43 | input: { 44 | function f(x) { 45 | function g() { 46 | if (x); 47 | else console.log("PASS"); 48 | } 49 | g(); 50 | } 51 | f(0); 52 | } 53 | expect: { 54 | function f(x) { 55 | (function() { 56 | if (x); 57 | else console.log("PASS"); 58 | })(); 59 | } 60 | f(0); 61 | } 62 | expect_stdout: "PASS" 63 | } 64 | 65 | side_effects_finally: { 66 | options = { 67 | reduce_funcs: true, 68 | reduce_vars: true, 69 | side_effects: true, 70 | unused: true, 71 | } 72 | input: { 73 | function f() { 74 | function g() { 75 | try { 76 | x(); 77 | } catch (e) { 78 | } finally { 79 | console.log("PASS"); 80 | } 81 | } 82 | g(); 83 | } 84 | f(); 85 | } 86 | expect: { 87 | function f() { 88 | (function() { 89 | try { 90 | x(); 91 | } catch (e) { 92 | } finally { 93 | console.log("PASS"); 94 | } 95 | })(); 96 | } 97 | f(); 98 | } 99 | expect_stdout: "PASS" 100 | } 101 | 102 | side_effects_label: { 103 | options = { 104 | reduce_funcs: true, 105 | reduce_vars: true, 106 | side_effects: true, 107 | unused: true, 108 | } 109 | input: { 110 | function f(x) { 111 | function g() { 112 | L: { 113 | console.log("PASS"); 114 | break L; 115 | } 116 | } 117 | g(); 118 | } 119 | f(0); 120 | } 121 | expect: { 122 | function f(x) { 123 | (function() { 124 | L: { 125 | console.log("PASS"); 126 | break L; 127 | } 128 | })(); 129 | } 130 | f(0); 131 | } 132 | expect_stdout: "PASS" 133 | } 134 | 135 | side_effects_switch: { 136 | options = { 137 | reduce_funcs: true, 138 | reduce_vars: true, 139 | side_effects: true, 140 | unused: true, 141 | } 142 | input: { 143 | function f() { 144 | function g() { 145 | switch (0) { 146 | default: 147 | case console.log("PASS"): 148 | } 149 | } 150 | g(); 151 | } 152 | f(); 153 | } 154 | expect: { 155 | function f() { 156 | (function() { 157 | switch (0) { 158 | default: 159 | case console.log("PASS"): 160 | } 161 | })(); 162 | } 163 | f(); 164 | } 165 | expect_stdout: "PASS" 166 | } 167 | -------------------------------------------------------------------------------- /test/compress/issue-1733.js: -------------------------------------------------------------------------------- 1 | function_iife_catch: { 2 | mangle = { 3 | ie: false, 4 | } 5 | input: { 6 | function f(n) { 7 | !function() { 8 | try { 9 | throw 0; 10 | } catch (n) { 11 | var a = 1; 12 | console.log(n, a); 13 | } 14 | }(); 15 | } 16 | f(); 17 | } 18 | expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();" 19 | expect_stdout: "0 1" 20 | } 21 | 22 | function_iife_catch_ie8: { 23 | mangle = { 24 | ie: true, 25 | } 26 | input: { 27 | function f(n) { 28 | !function() { 29 | try { 30 | throw 0; 31 | } catch (n) { 32 | var a = 1; 33 | console.log(n, a); 34 | } 35 | }(); 36 | } 37 | f(); 38 | } 39 | expect_exact: "function f(c){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();" 40 | expect_stdout: "0 1" 41 | } 42 | 43 | function_catch_catch: { 44 | mangle = { 45 | ie: false, 46 | } 47 | input: { 48 | var o = 0; 49 | function f() { 50 | try { 51 | throw 1; 52 | } catch (c) { 53 | try { 54 | throw 2; 55 | } catch (o) { 56 | var o = 3; 57 | console.log(o); 58 | } 59 | } 60 | console.log(o); 61 | } 62 | f(); 63 | } 64 | expect_exact: "var o=0;function f(){try{throw 1}catch(o){try{throw 2}catch(c){var c=3;console.log(c)}}console.log(c)}f();" 65 | expect_stdout: [ 66 | "3", 67 | "undefined", 68 | ] 69 | } 70 | 71 | function_catch_catch_ie8: { 72 | mangle = { 73 | ie: true, 74 | } 75 | input: { 76 | var o = 0; 77 | function f() { 78 | try { 79 | throw 1; 80 | } catch (c) { 81 | try { 82 | throw 2; 83 | } catch (o) { 84 | var o = 3; 85 | console.log(o); 86 | } 87 | } 88 | console.log(o); 89 | } 90 | f(); 91 | } 92 | 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();" 93 | expect_stdout: [ 94 | "3", 95 | "undefined", 96 | ] 97 | } 98 | -------------------------------------------------------------------------------- /test/compress/issue-1750.js: -------------------------------------------------------------------------------- 1 | case_1: { 2 | options = { 3 | dead_code: true, 4 | evaluate: true, 5 | switches: true, 6 | } 7 | input: { 8 | var a = 0, b = 1; 9 | switch (true) { 10 | case a || true: 11 | default: 12 | b = 2; 13 | case true: 14 | } 15 | console.log(a, b); 16 | } 17 | expect: { 18 | var a = 0, b = 1; 19 | switch (true) { 20 | case a || true: 21 | b = 2; 22 | } 23 | console.log(a, b); 24 | } 25 | expect_stdout: "0 2" 26 | } 27 | 28 | case_2: { 29 | options = { 30 | dead_code: true, 31 | evaluate: true, 32 | switches: true, 33 | } 34 | input: { 35 | var a = 0, b = 1; 36 | switch (0) { 37 | default: 38 | b = 2; 39 | case a: 40 | a = 3; 41 | case 0: 42 | } 43 | console.log(a, b); 44 | } 45 | expect: { 46 | var a = 0, b = 1; 47 | switch (0) { 48 | case a: 49 | a = 3; 50 | } 51 | console.log(a, b); 52 | } 53 | expect_stdout: "3 1" 54 | } 55 | -------------------------------------------------------------------------------- /test/compress/issue-1787.js: -------------------------------------------------------------------------------- 1 | unary_prefix: { 2 | options = { 3 | evaluate: true, 4 | inline: true, 5 | reduce_funcs: true, 6 | reduce_vars: true, 7 | unused: true, 8 | } 9 | input: { 10 | console.log(function() { 11 | var x = -(2 / 3); 12 | return x; 13 | }()); 14 | } 15 | expect_exact: "console.log(-2/3);" 16 | expect_stdout: true 17 | } 18 | -------------------------------------------------------------------------------- /test/compress/issue-1833.js: -------------------------------------------------------------------------------- 1 | iife_for: { 2 | options = { 3 | negate_iife: true, 4 | reduce_funcs: true, 5 | reduce_vars: true, 6 | toplevel: true, 7 | unused: true, 8 | } 9 | input: { 10 | function f() { 11 | function g() { 12 | L: for (;;) break L; 13 | } 14 | g(); 15 | } 16 | f(); 17 | } 18 | expect: { 19 | !function() { 20 | !function() { 21 | L: for (;;) break L; 22 | }(); 23 | }(); 24 | } 25 | } 26 | 27 | iife_for_in: { 28 | options = { 29 | negate_iife: true, 30 | reduce_funcs: true, 31 | reduce_vars: true, 32 | toplevel: true, 33 | unused: true, 34 | } 35 | input: { 36 | function f() { 37 | function g() { 38 | L: for (var a in x) break L; 39 | } 40 | g(); 41 | } 42 | f(); 43 | } 44 | expect: { 45 | !function() { 46 | !function() { 47 | L: for (var a in x) break L; 48 | }(); 49 | }(); 50 | } 51 | } 52 | 53 | iife_do: { 54 | options = { 55 | negate_iife: true, 56 | reduce_funcs: true, 57 | reduce_vars: true, 58 | toplevel: true, 59 | unused: true, 60 | } 61 | input: { 62 | function f() { 63 | function g() { 64 | L: do { 65 | break L; 66 | } while (1); 67 | } 68 | g(); 69 | } 70 | f(); 71 | } 72 | expect: { 73 | !function() { 74 | !function() { 75 | L: do { 76 | break L; 77 | } while (1); 78 | }(); 79 | }(); 80 | } 81 | } 82 | 83 | iife_while: { 84 | options = { 85 | negate_iife: true, 86 | reduce_funcs: true, 87 | reduce_vars: true, 88 | toplevel: true, 89 | unused: true, 90 | } 91 | input: { 92 | function f() { 93 | function g() { 94 | L: while (1) break L; 95 | } 96 | g(); 97 | } 98 | f(); 99 | } 100 | expect: { 101 | !function() { 102 | !function() { 103 | L: while (1) break L; 104 | }(); 105 | }(); 106 | } 107 | } 108 | 109 | label_do: { 110 | options = { 111 | evaluate: true, 112 | loops: true, 113 | } 114 | input: { 115 | L: do { 116 | continue L; 117 | } while (0); 118 | } 119 | expect: { 120 | L: do { 121 | continue L; 122 | } while (0); 123 | } 124 | } 125 | 126 | label_while: { 127 | options = { 128 | dead_code: true, 129 | evaluate: true, 130 | loops: true, 131 | } 132 | input: { 133 | function f() { 134 | L: while (0) continue L; 135 | } 136 | } 137 | expect_exact: "function f(){L:0}" 138 | } 139 | -------------------------------------------------------------------------------- /test/compress/issue-1943.js: -------------------------------------------------------------------------------- 1 | operator: { 2 | input: { 3 | a. //comment 4 | typeof 5 | } 6 | expect_exact: "a.typeof;" 7 | } 8 | 9 | name: { 10 | input: { 11 | a. //comment 12 | b 13 | } 14 | expect_exact: "a.b;" 15 | } 16 | 17 | keyword: { 18 | input: { 19 | a. //comment 20 | default 21 | } 22 | expect_exact: "a.default;" 23 | } 24 | 25 | atom: { 26 | input: { 27 | a. //comment 28 | true 29 | } 30 | expect_exact: "a.true;" 31 | } 32 | -------------------------------------------------------------------------------- /test/compress/issue-208.js: -------------------------------------------------------------------------------- 1 | do_not_update_lhs: { 2 | options = { 3 | global_defs: { 4 | DEBUG: 0, 5 | }, 6 | } 7 | input: { 8 | DEBUG++; 9 | DEBUG += 1; 10 | DEBUG = 1; 11 | } 12 | expect: { 13 | DEBUG++; 14 | DEBUG += 1; 15 | DEBUG = 1; 16 | } 17 | } 18 | 19 | do_update_rhs: { 20 | options = { 21 | global_defs: { 22 | DEBUG: 0, 23 | }, 24 | } 25 | input: { 26 | MY_DEBUG = DEBUG; 27 | MY_DEBUG += DEBUG; 28 | } 29 | expect: { 30 | MY_DEBUG = 0; 31 | MY_DEBUG += 0; 32 | } 33 | } 34 | 35 | mixed: { 36 | options = { 37 | evaluate: true, 38 | global_defs: { 39 | DEBUG: 0, 40 | ENV: 1, 41 | FOO: 2, 42 | }, 43 | } 44 | input: { 45 | var ENV = 3; 46 | var FOO = 4; 47 | f(ENV * 10); 48 | --FOO; 49 | DEBUG = 1; 50 | DEBUG++; 51 | DEBUG += 1; 52 | f(DEBUG); 53 | x = DEBUG; 54 | } 55 | expect: { 56 | var ENV = 3; 57 | var FOO = 4; 58 | f(10); 59 | --FOO; 60 | DEBUG = 1; 61 | DEBUG++; 62 | DEBUG += 1; 63 | f(0); 64 | x = 0; 65 | } 66 | expect_warnings: [ 67 | "WARN: global_defs ENV redefined [test/compress/issue-208.js:1,12]", 68 | "WARN: global_defs FOO redefined [test/compress/issue-208.js:2,12]", 69 | "WARN: global_defs FOO redefined [test/compress/issue-208.js:4,10]", 70 | "WARN: global_defs DEBUG redefined [test/compress/issue-208.js:5,8]", 71 | "WARN: global_defs DEBUG redefined [test/compress/issue-208.js:6,8]", 72 | "WARN: global_defs DEBUG redefined [test/compress/issue-208.js:7,8]", 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /test/compress/issue-22.js: -------------------------------------------------------------------------------- 1 | return_with_no_value_in_if_body: { 2 | options = { 3 | conditionals: true, 4 | } 5 | input: { 6 | function foo(bar) { 7 | if (bar) { 8 | return; 9 | } else { 10 | return 1; 11 | } 12 | } 13 | } 14 | expect: { 15 | function foo (bar) { 16 | return bar ? void 0 : 1; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/compress/issue-2652.js: -------------------------------------------------------------------------------- 1 | insert_semicolon: { 2 | beautify = { 3 | beautify: true, 4 | comments: "all", 5 | } 6 | input: { 7 | var a 8 | /* foo */ var b 9 | } 10 | expect_exact: [ 11 | "var a", 12 | "/* foo */;", 13 | "", 14 | "var b;", 15 | ] 16 | } 17 | 18 | unary_postfix: { 19 | beautify = { 20 | beautify: true, 21 | comments: "all", 22 | } 23 | input: { 24 | a 25 | /* foo */++b 26 | } 27 | expect_exact: [ 28 | "a", 29 | "/* foo */;", 30 | "", 31 | "++b;", 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /test/compress/issue-267.js: -------------------------------------------------------------------------------- 1 | issue_267: { 2 | options = { 3 | comparisons: true, 4 | } 5 | input: { 6 | x = a % b / b * c * 2; 7 | x = a % b * 2 8 | } 9 | expect: { 10 | x = a % b / b * c * 2; 11 | x = a % b * 2; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/compress/issue-269.js: -------------------------------------------------------------------------------- 1 | issue_269_1: { 2 | options = { 3 | unsafe: true, 4 | } 5 | input: { 6 | var x = {}; 7 | console.log( 8 | String(x), 9 | Number(x), 10 | Boolean(x), 11 | 12 | String(), 13 | Number(), 14 | Boolean() 15 | ); 16 | } 17 | expect: { 18 | var x = {}; 19 | console.log( 20 | "" + x, +("" + x), !!x, 21 | "", 0, false 22 | ); 23 | } 24 | expect_stdout: true 25 | } 26 | 27 | issue_269_dangers: { 28 | options = { 29 | unsafe: true, 30 | } 31 | input: { 32 | var x = {}; 33 | console.log( 34 | String(x, x), 35 | Number(x, x), 36 | Boolean(x, x) 37 | ); 38 | } 39 | expect: { 40 | var x = {}; 41 | console.log(String(x, x), Number(x, x), Boolean(x, x)); 42 | } 43 | expect_stdout: true 44 | } 45 | 46 | issue_269_in_scope: { 47 | options = { 48 | unsafe: true, 49 | } 50 | input: { 51 | var String, Number, Boolean; 52 | var x = {}; 53 | console.log( 54 | String(x), 55 | Number(x, x), 56 | Boolean(x) 57 | ); 58 | } 59 | expect: { 60 | var String, Number, Boolean; 61 | var x = {}; 62 | console.log(String(x), Number(x, x), Boolean(x)); 63 | } 64 | expect_stdout: true 65 | } 66 | 67 | strings_concat: { 68 | options = { 69 | strings: true, 70 | unsafe: true, 71 | } 72 | input: { 73 | var x = {}; 74 | console.log( 75 | String(x + "str"), 76 | String("str" + x) 77 | ); 78 | } 79 | expect: { 80 | var x = {}; 81 | console.log( 82 | x + "str", 83 | "str" + x 84 | ); 85 | } 86 | expect_stdout: true 87 | } 88 | 89 | regexp: { 90 | options = { 91 | evaluate: true, 92 | unsafe: true, 93 | } 94 | input: { 95 | RegExp("foo"); 96 | RegExp("bar", "ig"); 97 | RegExp(foo); 98 | RegExp("bar", ig); 99 | RegExp("should", "fail"); 100 | } 101 | expect: { 102 | /foo/; 103 | /bar/ig; 104 | RegExp(foo); 105 | RegExp("bar", ig); 106 | RegExp("should", "fail"); 107 | } 108 | expect_warnings: [ 109 | 'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,8]', 110 | ] 111 | } 112 | -------------------------------------------------------------------------------- /test/compress/issue-2719.js: -------------------------------------------------------------------------------- 1 | warn: { 2 | options = { 3 | evaluate: true, 4 | inline: true, 5 | passes: 2, 6 | properties: true, 7 | reduce_funcs: true, 8 | reduce_vars: true, 9 | toplevel: true, 10 | unused: true, 11 | } 12 | input: { 13 | function f() { 14 | return g(); 15 | } 16 | function g() { 17 | return g["call" + "er"].arguments; 18 | } 19 | // 3 20 | console.log(f(1, 2, 3).length); 21 | } 22 | expect: { 23 | // TypeError: Cannot read property 'arguments' of null 24 | console.log(function g() { 25 | return g.caller.arguments; 26 | }().length); 27 | } 28 | expect_warnings: [ 29 | "WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]", 30 | "WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]", 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/compress/issue-2871.js: -------------------------------------------------------------------------------- 1 | comparison_with_undefined: { 2 | options = { 3 | comparisons: true, 4 | } 5 | input: { 6 | a == undefined; 7 | a != undefined; 8 | a === undefined; 9 | a !== undefined; 10 | 11 | undefined == a; 12 | undefined != a; 13 | undefined === a; 14 | undefined !== a; 15 | 16 | void 0 == a; 17 | void 0 != a; 18 | void 0 === a; 19 | void 0 !== a; 20 | } 21 | expect: { 22 | null == a; 23 | null != a; 24 | void 0 === a; 25 | void 0 !== a; 26 | 27 | null == a; 28 | null != a; 29 | void 0 === a; 30 | void 0 !== a; 31 | 32 | null == a; 33 | null != a; 34 | void 0 === a; 35 | void 0 !== a; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/compress/issue-2989.js: -------------------------------------------------------------------------------- 1 | inline_script_off: { 2 | beautify = { 3 | inline_script: false, 4 | } 5 | input: { 6 | console.log(""); 7 | } 8 | expect_exact: 'console.log("");' 9 | expect_stdout: "" 10 | } 11 | 12 | inline_script_on: { 13 | beautify = { 14 | inline_script: true, 15 | } 16 | input: { 17 | console.log(""); 18 | } 19 | expect_exact: 'console.log("<\\/sCrIpT>");' 20 | expect_stdout: "" 21 | } 22 | -------------------------------------------------------------------------------- /test/compress/issue-368.js: -------------------------------------------------------------------------------- 1 | collapse: { 2 | options = { 3 | collapse_vars: true, 4 | sequences: true, 5 | side_effects: true, 6 | unused: true, 7 | } 8 | input: { 9 | function f1() { 10 | var a; 11 | a = typeof b === 'function' ? b() : b; 12 | return a !== undefined && c(); 13 | } 14 | function f2(b) { 15 | var a; 16 | b = c(); 17 | a = typeof b === 'function' ? b() : b; 18 | return 'string' == typeof a && d(); 19 | } 20 | function f3(c) { 21 | var a; 22 | a = b(a / 2); 23 | if (a < 0) { 24 | a++; 25 | ++c; 26 | return c / 2; 27 | } 28 | } 29 | function f4(c) { 30 | var a; 31 | a = b(a / 2); 32 | if (a < 0) { 33 | a++; 34 | c++; 35 | return c / 2; 36 | } 37 | } 38 | } 39 | expect: { 40 | function f1() { 41 | return void 0 !== ('function' === typeof b ? b() : b) && c(); 42 | } 43 | function f2(b) { 44 | return 'string' == typeof ('function' === typeof (b = c()) ? b() : b) && d(); 45 | } 46 | function f3(c) { 47 | var a; 48 | if ((a = b(a / 2)) < 0) return a++, ++c / 2; 49 | } 50 | function f4(c) { 51 | var a; 52 | if ((a = b(a / 2)) < 0) return a++, ++c / 2; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/compress/issue-3768.js: -------------------------------------------------------------------------------- 1 | mangle: { 2 | mangle = { 3 | toplevel: true, 4 | } 5 | input: { 6 | var e = eval, x = 42; 7 | (function() { 8 | console.log(e("typeof x")); 9 | })(); 10 | } 11 | expect: { 12 | var e = eval, x = 42; 13 | (function() { 14 | console.log(e("typeof x")); 15 | })(); 16 | } 17 | expect_stdout: true 18 | } 19 | 20 | compress: { 21 | options = { 22 | collapse_vars: true, 23 | inline: true, 24 | unused: true, 25 | } 26 | input: { 27 | console.log(function() { 28 | var a = 42; 29 | return eval("typeof a"); 30 | }(), function(e) { 31 | var a = null; 32 | return e("typeof a"); 33 | }(eval), function(eval) { 34 | var a = false; 35 | return eval("typeof a"); 36 | }(eval), function(f) { 37 | var a = "STRING"; 38 | var eval = f; 39 | return eval("typeof a"); 40 | }(eval), function(g) { 41 | var a = eval; 42 | function eval() { 43 | return g; 44 | } 45 | return eval()("typeof a"); 46 | }(eval)); 47 | } 48 | expect: { 49 | console.log(function() { 50 | var a = 42; 51 | return eval("typeof a"); 52 | }(), (0, eval)("typeof a"), function(eval) { 53 | var a = false; 54 | return eval("typeof a"); 55 | }(eval), function(f) { 56 | var a = "STRING"; 57 | var eval = f; 58 | return eval("typeof a"); 59 | }(eval), function(g) { 60 | var a = eval; 61 | function eval() { 62 | return g; 63 | } 64 | return eval()("typeof a"); 65 | }(eval)); 66 | } 67 | expect_stdout: "number undefined boolean string undefined" 68 | } 69 | 70 | call_arg_1: { 71 | mangle = { 72 | toplevel: true, 73 | } 74 | input: { 75 | var z = "foo"; 76 | (function() { 77 | var z = false; 78 | (function(e) { 79 | var z = 42; 80 | e("console.log(typeof z)"); 81 | })(eval); 82 | })(); 83 | } 84 | expect: { 85 | var z = "foo"; 86 | (function() { 87 | var o = false; 88 | (function(o) { 89 | var a = 42; 90 | o("console.log(typeof z)"); 91 | })(eval); 92 | })(); 93 | } 94 | expect_stdout: true 95 | } 96 | 97 | call_arg_2: { 98 | mangle = { 99 | toplevel: true, 100 | } 101 | input: { 102 | function eval() { 103 | console.log("PASS"); 104 | } 105 | var z = "foo"; 106 | (function() { 107 | var z = false; 108 | (function(e) { 109 | var z = 42; 110 | e("console.log(typeof z)"); 111 | })(eval); 112 | })(); 113 | } 114 | expect: { 115 | function n() { 116 | console.log("PASS"); 117 | } 118 | var o = "foo"; 119 | (function() { 120 | var o = false; 121 | (function(o) { 122 | var n = 42; 123 | o("console.log(typeof z)"); 124 | })(n); 125 | })(); 126 | } 127 | expect_stdout: "PASS" 128 | } 129 | -------------------------------------------------------------------------------- /test/compress/issue-44.js: -------------------------------------------------------------------------------- 1 | issue_44_valid_ast_1: { 2 | options = { 3 | unused: true, 4 | } 5 | input: { 6 | function a(b) { 7 | for (var i = 0, e = b.qoo(); ; i++) {} 8 | } 9 | } 10 | expect: { 11 | function a(b) { 12 | var i = 0; 13 | for (b.qoo(); ; i++); 14 | } 15 | } 16 | } 17 | 18 | issue_44_valid_ast_2: { 19 | options = { 20 | unused: true, 21 | } 22 | input: { 23 | function a(b) { 24 | if (foo) for (var i = 0, e = b.qoo(); ; i++) {} 25 | } 26 | } 27 | expect: { 28 | function a(b) { 29 | if (foo) { 30 | var i = 0; 31 | for (b.qoo(); ; i++); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/compress/issue-59.js: -------------------------------------------------------------------------------- 1 | keep_continue: { 2 | options = { 3 | dead_code: true, 4 | evaluate: true, 5 | } 6 | input: { 7 | while (a) { 8 | if (b) { 9 | switch (true) { 10 | case c(): 11 | d(); 12 | } 13 | continue; 14 | } 15 | f(); 16 | } 17 | } 18 | expect: { 19 | while (a) { 20 | if (b) { 21 | switch (true) { 22 | case c(): 23 | d(); 24 | } 25 | continue; 26 | } 27 | f(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/compress/issue-597.js: -------------------------------------------------------------------------------- 1 | NaN_and_Infinity_must_have_parens: { 2 | options = {} 3 | input: { 4 | Infinity.toString(); 5 | NaN.toString(); 6 | } 7 | expect: { 8 | (1/0).toString(); 9 | NaN.toString(); 10 | } 11 | } 12 | 13 | NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: { 14 | options = {} 15 | input: { 16 | var Infinity, NaN; 17 | Infinity.toString(); 18 | NaN.toString(); 19 | } 20 | expect: { 21 | var Infinity, NaN; 22 | Infinity.toString(); 23 | NaN.toString(); 24 | } 25 | } 26 | 27 | NaN_and_Infinity_must_have_parens_evaluate: { 28 | options = { 29 | evaluate: true, 30 | } 31 | input: { 32 | (123456789 / 0).toString(); 33 | (+"foo").toString(); 34 | } 35 | expect: { 36 | (1/0).toString(); 37 | NaN.toString(); 38 | } 39 | } 40 | 41 | NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined_evaluate: { 42 | options = { 43 | evaluate: true, 44 | } 45 | input: { 46 | var Infinity, NaN; 47 | (123456789 / 0).toString(); 48 | (+"foo").toString(); 49 | } 50 | expect: { 51 | var Infinity, NaN; 52 | (1/0).toString(); 53 | (0/0).toString(); 54 | } 55 | } 56 | 57 | beautify_off_1: { 58 | options = { 59 | evaluate: true, 60 | } 61 | beautify = { 62 | beautify: false, 63 | } 64 | input: { 65 | var NaN; 66 | console.log( 67 | null, 68 | undefined, 69 | Infinity, 70 | NaN, 71 | Infinity * undefined, 72 | Infinity.toString(), 73 | NaN.toString(), 74 | (Infinity * undefined).toString() 75 | ); 76 | } 77 | expect_exact: "var NaN;console.log(null,void 0,1/0,NaN,0/0,(1/0).toString(),NaN.toString(),(0/0).toString());" 78 | expect_stdout: true 79 | } 80 | 81 | beautify_off_2: { 82 | options = { 83 | evaluate: true, 84 | } 85 | beautify = { 86 | beautify: false, 87 | } 88 | input: { 89 | console.log( 90 | null.toString(), 91 | undefined.toString() 92 | ); 93 | } 94 | expect_exact: "console.log(null.toString(),(void 0).toString());" 95 | } 96 | 97 | beautify_on_1: { 98 | options = { 99 | evaluate: true, 100 | } 101 | beautify = { 102 | beautify: true, 103 | } 104 | input: { 105 | var NaN; 106 | console.log( 107 | null, 108 | undefined, 109 | Infinity, 110 | NaN, 111 | Infinity * undefined, 112 | Infinity.toString(), 113 | NaN.toString(), 114 | (Infinity * undefined).toString() 115 | ); 116 | } 117 | expect_exact: [ 118 | "var NaN;", 119 | "", 120 | "console.log(null, void 0, 1 / 0, NaN, 0 / 0, (1 / 0).toString(), NaN.toString(), (0 / 0).toString());", 121 | ] 122 | expect_stdout: true 123 | } 124 | 125 | beautify_on_2: { 126 | options = { 127 | evaluate: true, 128 | } 129 | beautify = { 130 | beautify: true, 131 | } 132 | input: { 133 | console.log( 134 | null.toString(), 135 | undefined.toString() 136 | ); 137 | } 138 | expect_exact: "console.log(null.toString(), (void 0).toString());" 139 | } 140 | 141 | issue_1724: { 142 | input: { 143 | var a = 0; 144 | ++a % Infinity | Infinity ? a++ : 0; 145 | console.log(a); 146 | } 147 | expect_exact: "var a=0;++a%(1/0)|1/0?a++:0;console.log(a);" 148 | expect_stdout: "2" 149 | } 150 | 151 | issue_1725: { 152 | input: { 153 | ([].length === 0) % Infinity ? console.log("PASS") : console.log("FAIL"); 154 | } 155 | expect_exact: '(0===[].length)%(1/0)?console.log("PASS"):console.log("FAIL");' 156 | expect_stdout: "PASS" 157 | } 158 | -------------------------------------------------------------------------------- /test/compress/issue-611.js: -------------------------------------------------------------------------------- 1 | issue_611: { 2 | options = { 3 | sequences: true, 4 | side_effects: true, 5 | } 6 | input: { 7 | define(function() { 8 | function fn() {} 9 | if (fn()) { 10 | fn(); 11 | return void 0; 12 | } 13 | }); 14 | } 15 | expect: { 16 | define(function() { 17 | function fn(){} 18 | if (fn()) return void fn(); 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/compress/issue-637.js: -------------------------------------------------------------------------------- 1 | wrongly_optimized: { 2 | options = { 3 | booleans: true, 4 | conditionals: true, 5 | evaluate: true, 6 | } 7 | input: { 8 | function func() { 9 | foo(); 10 | } 11 | if (func() || true) { 12 | bar(); 13 | } 14 | } 15 | expect: { 16 | function func() { 17 | foo(); 18 | } 19 | func(), 1, bar(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/compress/issue-747.js: -------------------------------------------------------------------------------- 1 | dont_reuse_prop: { 2 | mangle = { 3 | properties: { 4 | domprops: true, 5 | regex: /asd/, 6 | }, 7 | } 8 | input: { 9 | "aaaaaaaaaabbbbb"; 10 | var obj = {}; 11 | obj.a = 123; 12 | obj.asd = 256; 13 | console.log(obj.a); 14 | } 15 | expect: { 16 | "aaaaaaaaaabbbbb"; 17 | var obj = {}; 18 | obj.a = 123; 19 | obj.b = 256; 20 | console.log(obj.a); 21 | } 22 | expect_stdout: "123" 23 | expect_warnings: [ 24 | "INFO: Preserving excluded property a", 25 | "INFO: Mapping property asd to b", 26 | "INFO: Preserving reserved property log", 27 | ] 28 | } 29 | 30 | unmangleable_props_should_always_be_reserved: { 31 | mangle = { 32 | properties: { 33 | domprops: true, 34 | regex: /asd/, 35 | }, 36 | } 37 | input: { 38 | "aaaaaaaaaabbbbb"; 39 | var obj = {}; 40 | obj.asd = 256; 41 | obj.a = 123; 42 | console.log(obj.a); 43 | } 44 | expect: { 45 | "aaaaaaaaaabbbbb"; 46 | var obj = {}; 47 | obj.b = 256; 48 | obj.a = 123; 49 | console.log(obj.a); 50 | } 51 | expect_stdout: "123" 52 | expect_warnings: [ 53 | "INFO: Preserving excluded property a", 54 | "INFO: Mapping property asd to b", 55 | "INFO: Preserving reserved property log", 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /test/compress/issue-751.js: -------------------------------------------------------------------------------- 1 | negate_booleans_1: { 2 | options = { 3 | comparisons: true, 4 | } 5 | input: { 6 | var a = !a || !b || !c || !d || !e || !f; 7 | } 8 | expect: { 9 | var a = !(a && b && c && d && e && f); 10 | } 11 | } 12 | 13 | negate_booleans_2: { 14 | options = { 15 | comparisons: true, 16 | } 17 | input: { 18 | var match = !x && // should not touch this one 19 | (!z || c) && 20 | (!k || d) && 21 | the_stuff(); 22 | } 23 | expect: { 24 | var match = !x && 25 | (!z || c) && 26 | (!k || d) && 27 | the_stuff(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/compress/issue-782.js: -------------------------------------------------------------------------------- 1 | remove_sequence: { 2 | options = { 3 | side_effects: true, 4 | } 5 | input: { 6 | (0, 1, eval)(); 7 | (0, 1, logThis)(); 8 | (0, 1, _decorators.logThis)(); 9 | } 10 | expect: { 11 | (0, eval)(); 12 | logThis(); 13 | (0, _decorators.logThis)(); 14 | } 15 | } 16 | 17 | remove_redundant_sequence_items: { 18 | options = { 19 | side_effects: true, 20 | } 21 | input: { 22 | "use strict"; 23 | (0, 1, eval)(); 24 | (0, 1, logThis)(); 25 | (0, 1, _decorators.logThis)(); 26 | } 27 | expect: { 28 | "use strict"; 29 | (0, eval)(); 30 | logThis(); 31 | (0, _decorators.logThis)(); 32 | } 33 | } 34 | 35 | dont_remove_this_binding_sequence: { 36 | options = { 37 | side_effects: true, 38 | } 39 | input: { 40 | "use strict"; 41 | (0, eval)(); 42 | (0, logThis)(); 43 | (0, _decorators.logThis)(); 44 | } 45 | expect: { 46 | "use strict"; 47 | (0, eval)(); 48 | logThis(); 49 | (0, _decorators.logThis)(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/compress/issue-892.js: -------------------------------------------------------------------------------- 1 | dont_mangle_arguments: { 2 | options = { 3 | booleans: true, 4 | comparisons: true, 5 | conditionals: true, 6 | dead_code: true, 7 | drop_debugger: true, 8 | evaluate: true, 9 | hoist_funs: true, 10 | hoist_vars: true, 11 | if_return: true, 12 | join_vars: true, 13 | keep_fargs: true, 14 | keep_fnames: false, 15 | loops: true, 16 | negate_iife: false, 17 | properties: true, 18 | sequences: true, 19 | side_effects: true, 20 | unused: true, 21 | } 22 | mangle = {} 23 | input: { 24 | (function(){ 25 | var arguments = arguments, not_arguments = 9; 26 | console.log(not_arguments, arguments); 27 | })(5, 6, 7); 28 | } 29 | expect_exact: "(function(){var arguments,o=9;console.log(o,arguments)})(5,6,7);" 30 | expect_stdout: true 31 | } 32 | -------------------------------------------------------------------------------- /test/compress/issue-913.js: -------------------------------------------------------------------------------- 1 | keep_var_for_in: { 2 | options = { 3 | hoist_vars: true, 4 | join_vars: true, 5 | unused: true, 6 | } 7 | input: { 8 | (function(obj) { 9 | var foo = 5; 10 | for (var i in obj) 11 | return foo; 12 | })(); 13 | } 14 | expect: { 15 | (function(obj) { 16 | var i, foo = 5; 17 | for (i in obj) 18 | return foo; 19 | })(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/compress/issue-973.js: -------------------------------------------------------------------------------- 1 | this_binding_conditionals: { 2 | options = { 3 | conditionals: true, 4 | evaluate: true, 5 | side_effects: true, 6 | } 7 | input: { 8 | "use strict"; 9 | (1 && a)(); 10 | (0 || a)(); 11 | (0 || 1 && a)(); 12 | (1 ? a : 0)(); 13 | 14 | (1 && a.b)(); 15 | (0 || a.b)(); 16 | (0 || 1 && a.b)(); 17 | (1 ? a.b : 0)(); 18 | 19 | (1 && a[b])(); 20 | (0 || a[b])(); 21 | (0 || 1 && a[b])(); 22 | (1 ? a[b] : 0)(); 23 | 24 | (1 && eval)(); 25 | (0 || eval)(); 26 | (0 || 1 && eval)(); 27 | (1 ? eval : 0)(); 28 | } 29 | expect: { 30 | "use strict"; 31 | a(); 32 | a(); 33 | a(); 34 | a(); 35 | 36 | (0, a.b)(); 37 | (0, a.b)(); 38 | (0, a.b)(); 39 | (0, a.b)(); 40 | 41 | (0, a[b])(); 42 | (0, a[b])(); 43 | (0, a[b])(); 44 | (0, a[b])(); 45 | 46 | (0, eval)(); 47 | (0, eval)(); 48 | (0, eval)(); 49 | (0, eval)(); 50 | } 51 | } 52 | 53 | this_binding_collapse_vars: { 54 | options = { 55 | collapse_vars: true, 56 | unused: true, 57 | } 58 | input: { 59 | function f() { 60 | "use strict"; 61 | var c = a; c(); 62 | var d = a.b; d(); 63 | var e = eval; e(); 64 | } 65 | } 66 | expect: { 67 | function f() { 68 | "use strict"; 69 | a(); 70 | (0, a.b)(); 71 | (0, eval)(); 72 | } 73 | } 74 | } 75 | 76 | this_binding_side_effects: { 77 | options = { 78 | side_effects: true, 79 | } 80 | input: { 81 | (function(foo) { 82 | (0, foo)(); 83 | (0, foo.bar)(); 84 | (0, eval)("console.log(foo);"); 85 | }()); 86 | (function(foo) { 87 | "use strict"; 88 | (0, foo)(); 89 | (0, foo.bar)(); 90 | (0, eval)("console.log(foo);"); 91 | }()); 92 | (function(foo) { 93 | var eval = console; 94 | (0, foo)(); 95 | (0, foo.bar)(); 96 | (0, eval)("console.log(foo);"); 97 | }()); 98 | } 99 | expect: { 100 | (function(foo) { 101 | foo(); 102 | (0, foo.bar)(); 103 | (0, eval)("console.log(foo);"); 104 | }()); 105 | (function(foo) { 106 | "use strict"; 107 | foo(); 108 | (0, foo.bar)(); 109 | (0, eval)("console.log(foo);"); 110 | }()); 111 | (function(foo) { 112 | var eval = console; 113 | foo(); 114 | (0, foo.bar)(); 115 | eval("console.log(foo);"); 116 | }()); 117 | } 118 | } 119 | 120 | this_binding_sequences: { 121 | options = { 122 | sequences: true, 123 | side_effects: true, 124 | } 125 | input: { 126 | console.log(typeof function() { 127 | return eval("this"); 128 | }()); 129 | console.log(typeof function() { 130 | "use strict"; 131 | return eval("this"); 132 | }()); 133 | console.log(typeof function() { 134 | return (0, eval)("this"); 135 | }()); 136 | console.log(typeof function() { 137 | "use strict"; 138 | return (0, eval)("this"); 139 | }()); 140 | } 141 | expect: { 142 | console.log(typeof function() { 143 | return eval("this"); 144 | }()), 145 | console.log(typeof function() { 146 | "use strict"; 147 | return eval("this"); 148 | }()), 149 | console.log(typeof function() { 150 | return (0, eval)("this"); 151 | }()), 152 | console.log(typeof function() { 153 | "use strict"; 154 | return (0, eval)("this"); 155 | }()); 156 | } 157 | expect_stdout: [ 158 | "object", 159 | "undefined", 160 | "object", 161 | "object", 162 | ] 163 | } 164 | -------------------------------------------------------------------------------- /test/compress/issue-979.js: -------------------------------------------------------------------------------- 1 | reported: { 2 | options = { 3 | booleans: true, 4 | comparisons: true, 5 | conditionals: true, 6 | dead_code: true, 7 | evaluate: true, 8 | hoist_funs: true, 9 | if_return: true, 10 | join_vars: true, 11 | keep_fargs: true, 12 | loops: true, 13 | properties: true, 14 | sequences: true, 15 | side_effects: true, 16 | unused: true, 17 | } 18 | input: { 19 | function f1() { 20 | if (a == 1 || b == 2) 21 | foo(); 22 | } 23 | function f2() { 24 | if (!(a == 1 || b == 2)); 25 | else 26 | foo(); 27 | } 28 | } 29 | expect: { 30 | function f1() { 31 | 1 != a && 2 != b || foo(); 32 | } 33 | function f2() { 34 | 1 != a && 2 != b || foo(); 35 | } 36 | } 37 | } 38 | 39 | test_negated_is_best: { 40 | options = { 41 | booleans: true, 42 | comparisons: true, 43 | conditionals: true, 44 | dead_code: true, 45 | evaluate: true, 46 | hoist_funs: true, 47 | if_return: true, 48 | join_vars: true, 49 | keep_fargs: true, 50 | loops: true, 51 | properties: true, 52 | sequences: true, 53 | side_effects: true, 54 | unused: true, 55 | } 56 | input: { 57 | function f3() { 58 | if (a == 1 | b == 2) 59 | foo(); 60 | } 61 | function f4() { 62 | if (!(a == 1 | b == 2)); 63 | else 64 | foo(); 65 | } 66 | function f5() { 67 | if (a == 1 && b == 2) 68 | foo(); 69 | } 70 | function f6() { 71 | if (!(a == 1 && b == 2)); 72 | else 73 | foo(); 74 | } 75 | function f7() { 76 | if (a == 1 || b == 2) 77 | foo(); 78 | else 79 | return bar(); 80 | } 81 | } 82 | expect: { 83 | function f3() { 84 | 1 == a | 2 == b && foo(); 85 | } 86 | function f4() { 87 | 1 == a | 2 == b && foo(); 88 | } 89 | function f5() { 90 | 1 == a && 2 == b && foo(); 91 | } 92 | function f6() { 93 | 1 == a && 2 == b && foo(); 94 | } 95 | function f7() { 96 | if (1 != a && 2 != b) 97 | return bar(); 98 | foo(); 99 | } 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /test/compress/max_line_len.js: -------------------------------------------------------------------------------- 1 | too_short: { 2 | beautify = { 3 | max_line_len: 10, 4 | } 5 | input: { 6 | function f(a) { 7 | return { c: 42, d: a(), e: "foo"}; 8 | } 9 | } 10 | expect_exact: [ 11 | "function f(", 12 | "a){return{", 13 | "c:42,d:a(", 14 | '),e:"foo"}', 15 | "}", 16 | ] 17 | expect_warnings: [ 18 | "WARN: Output exceeds 10 characters", 19 | ] 20 | } 21 | 22 | just_enough: { 23 | beautify = { 24 | max_line_len: 14, 25 | } 26 | input: { 27 | function f(a) { 28 | return { c: 42, d: a(), e: "foo"}; 29 | } 30 | } 31 | expect_exact: [ 32 | "function f(a){", 33 | "return{c:42,", 34 | 'd:a(),e:"foo"}', 35 | "}", 36 | ] 37 | expect_warnings: [] 38 | } 39 | 40 | drop_semicolon: { 41 | beautify = { 42 | max_line_len: 5, 43 | semicolons: true, 44 | } 45 | input: { 46 | var a; 47 | console.log(a || 42); 48 | } 49 | expect_exact: [ 50 | "var a", 51 | "console.log(", 52 | "a||42", 53 | ");", 54 | ] 55 | expect_stdout: "42" 56 | expect_warnings: [ 57 | "WARN: Output exceeds 5 characters", 58 | ] 59 | } 60 | 61 | template_newline: { 62 | beautify = { 63 | max_line_len: 2, 64 | } 65 | input: { 66 | console.log(`foo 67 | bar`); 68 | } 69 | expect_exact: [ 70 | "console.log(", 71 | "`foo", 72 | "bar`", 73 | ");", 74 | ] 75 | expect_stdout: [ 76 | "foo", 77 | "bar", 78 | ] 79 | expect_warnings: [ 80 | "WARN: Output exceeds 2 characters", 81 | ] 82 | node_version: ">=4" 83 | } 84 | 85 | issue_304: { 86 | beautify = { 87 | max_line_len: 10, 88 | } 89 | input: { 90 | var a = 0, b = 0, c = 0, d = 0, e = 0; 91 | } 92 | expect_exact: [ 93 | "var a=0,", 94 | "b=0,c=0,", 95 | "d=0,e=0;", 96 | ] 97 | expect_warnings: [] 98 | } 99 | -------------------------------------------------------------------------------- /test/compress/new.js: -------------------------------------------------------------------------------- 1 | new_statement: { 2 | input: { 3 | new x(1); 4 | new x(1)(2); 5 | new x(1)(2)(3); 6 | new new x(1); 7 | new new x(1)(2); 8 | new (new x(1))(2); 9 | (new new x(1))(2); 10 | } 11 | 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);" 12 | } 13 | 14 | new_statements_2: { 15 | input: { 16 | new x; 17 | new new x; 18 | new new new x; 19 | new true; 20 | new (0); 21 | new (!0); 22 | new (bar = function(foo) {this.foo=foo;})(123); 23 | new (bar = function(foo) {this.foo=foo;})(); 24 | } 25 | 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});" 26 | } 27 | 28 | new_statements_3: { 29 | input: { 30 | new (function(foo){this.foo=foo;})(1); 31 | new (function(foo){this.foo=foo;})(); 32 | new (function test(foo){this.foo=foo;})(1); 33 | new (function test(foo){this.foo=foo;})(); 34 | } 35 | 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};" 36 | } 37 | 38 | new_with_rewritten_true_value: { 39 | options = { 40 | booleans: true, 41 | } 42 | input: { 43 | new true; 44 | } 45 | expect_exact: "new(!0);" 46 | } 47 | 48 | new_with_many_parameters: { 49 | input: { 50 | new foo.bar("baz"); 51 | new x(/123/, 456); 52 | } 53 | expect_exact: 'new foo.bar("baz");new x(/123/,456);' 54 | } 55 | 56 | new_constructor_with_unary_arguments: { 57 | input: { 58 | new x(); 59 | new x(-1); 60 | new x(-1, -2); 61 | new x(void 1, +2, -3, ~4, !5, --a, ++b, c--, d++, typeof e, delete f); 62 | new (-1); // should parse despite being invalid at runtime. 63 | new (-1)(); // should parse despite being invalid at runtime. 64 | new (-1)(-2); // should parse despite being invalid at runtime. 65 | } 66 | 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);" 67 | } 68 | 69 | call_with_unary_arguments: { 70 | input: { 71 | x(); 72 | x(-1); 73 | x(-1, -2); 74 | x(void 1, +2, -3, ~4, !5, --a, ++b, c--, d++, typeof e, delete f); 75 | (-1)(); // should parse despite being invalid at runtime. 76 | (-1)(-2); // should parse despite being invalid at runtime. 77 | } 78 | 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);" 79 | } 80 | 81 | new_with_unary_prefix: { 82 | input: { 83 | var bar = (+new Date()).toString(32); 84 | } 85 | expect_exact: 'var bar=(+new Date).toString(32);'; 86 | } 87 | 88 | dot_parentheses_1: { 89 | input: { 90 | console.log(new (Math.random().constructor) instanceof Number); 91 | } 92 | expect_exact: "console.log(new(Math.random().constructor)instanceof Number);" 93 | expect_stdout: "true" 94 | } 95 | 96 | dot_parentheses_2: { 97 | input: { 98 | console.log(typeof new function(){Math.random()}.constructor); 99 | } 100 | expect_exact: "console.log(typeof new function(){Math.random()}.constructor);" 101 | expect_stdout: "function" 102 | } 103 | -------------------------------------------------------------------------------- /test/compress/node_version.js: -------------------------------------------------------------------------------- 1 | eval_let_6: { 2 | input: { 3 | eval("let a;"); 4 | console.log(); 5 | } 6 | expect: { 7 | eval("let a;"); 8 | console.log(); 9 | } 10 | expect_stdout: "" 11 | node_version: ">=6" 12 | } 13 | 14 | eval_let_4: { 15 | input: { 16 | eval("let a;"); 17 | console.log(); 18 | } 19 | expect: { 20 | eval("let a;"); 21 | console.log(); 22 | } 23 | expect_stdout: SyntaxError("Block-scoped declarations (let, const, function, class) not yet supported outside strict mode") 24 | node_version: "4" 25 | } 26 | 27 | eval_let_0: { 28 | input: { 29 | eval("let a;"); 30 | console.log(); 31 | } 32 | expect: { 33 | eval("let a;"); 34 | console.log(); 35 | } 36 | expect_stdout: SyntaxError("Unexpected identifier") 37 | node_version: "<=0.12" 38 | } 39 | -------------------------------------------------------------------------------- /test/compress/return_undefined.js: -------------------------------------------------------------------------------- 1 | return_undefined: { 2 | options = { 3 | booleans: true, 4 | comparisons: true, 5 | conditionals: true, 6 | dead_code: true, 7 | drop_debugger: true, 8 | evaluate: true, 9 | hoist_funs: true, 10 | hoist_vars: true, 11 | if_return: true, 12 | join_vars: true, 13 | keep_fargs: true, 14 | keep_fnames: false, 15 | loops: true, 16 | negate_iife: true, 17 | properties: true, 18 | sequences: false, 19 | side_effects: true, 20 | unused: true, 21 | } 22 | input: { 23 | function f0() { 24 | } 25 | function f1() { 26 | return undefined; 27 | } 28 | function f2() { 29 | return void 0; 30 | } 31 | function f3() { 32 | return void 123; 33 | } 34 | function f4() { 35 | return; 36 | } 37 | function f5(a, b) { 38 | console.log(a, b); 39 | baz(a); 40 | return; 41 | } 42 | function f6(a, b) { 43 | console.log(a, b); 44 | if (a) { 45 | foo(b); 46 | baz(a); 47 | return a + b; 48 | } 49 | return undefined; 50 | } 51 | function f7(a, b) { 52 | console.log(a, b); 53 | if (a) { 54 | foo(b); 55 | baz(a); 56 | return void 0; 57 | } 58 | return a + b; 59 | } 60 | function f8(a, b) { 61 | foo(a); 62 | bar(b); 63 | return void 0; 64 | } 65 | function f9(a, b) { 66 | foo(a); 67 | bar(b); 68 | return undefined; 69 | } 70 | function f10() { 71 | return false; 72 | } 73 | function f11() { 74 | return null; 75 | } 76 | function f12() { 77 | return 0; 78 | } 79 | } 80 | expect: { 81 | function f0() {} 82 | function f1() {} 83 | function f2() {} 84 | function f3() {} 85 | function f4() {} 86 | function f5(a, b) { 87 | console.log(a, b); 88 | baz(a); 89 | } 90 | function f6(a, b) { 91 | console.log(a, b); 92 | if (a) { 93 | foo(b); 94 | baz(a); 95 | return a + b; 96 | } 97 | } 98 | function f7(a, b) { 99 | console.log(a, b); 100 | if (!a) 101 | return a + b; 102 | foo(b); 103 | baz(a); 104 | } 105 | function f8(a, b) { 106 | foo(a); 107 | bar(b); 108 | } 109 | function f9(a, b) { 110 | foo(a); 111 | bar(b); 112 | } 113 | function f10() { 114 | return !1; 115 | } 116 | function f11() { 117 | return null; 118 | } 119 | function f12() { 120 | return 0; 121 | } 122 | } 123 | } 124 | 125 | return_void: { 126 | options = { 127 | if_return: true, 128 | inline: true, 129 | reduce_vars: true, 130 | unused: true, 131 | } 132 | input: { 133 | function f() { 134 | function g() { 135 | h(); 136 | } 137 | return g(); 138 | } 139 | } 140 | expect: { 141 | function f() { 142 | h(); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /test/compress/string-literal.js: -------------------------------------------------------------------------------- 1 | octal_escape_sequence: { 2 | input: { 3 | var boundaries = "\0\7\00\07\70\77\000\077\300\377"; 4 | var border_check = "\400\700\0000\3000"; 5 | } 6 | expect: { 7 | var boundaries = "\x00\x07\x00\x07\x38\x3f\x00\x3f\xc0\xff"; 8 | var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30"; 9 | } 10 | } 11 | 12 | issue_1929: { 13 | input: { 14 | function f(s) { 15 | return s.split(/[\\/]/); 16 | } 17 | console.log(JSON.stringify(f("A/B\\C\\D/E\\F"))); 18 | } 19 | expect: { 20 | function f(s) { 21 | return s.split(/[\\/]/); 22 | } 23 | console.log(JSON.stringify(f("A/B\\C\\D/E\\F"))); 24 | } 25 | expect_stdout: '["A","B","C","D","E","F"]' 26 | } 27 | -------------------------------------------------------------------------------- /test/compress/transform.js: -------------------------------------------------------------------------------- 1 | booleans_evaluate: { 2 | options = { 3 | booleans: true, 4 | evaluate: true, 5 | } 6 | input: { 7 | console.log(typeof void 0 != "undefined"); 8 | console.log(1 == 1, 1 === 1) 9 | console.log(1 != 1, 1 !== 1) 10 | } 11 | expect: { 12 | console.log(!1); 13 | console.log(!0, !0); 14 | console.log(!1, !1); 15 | } 16 | expect_stdout: true 17 | } 18 | 19 | booleans_global_defs: { 20 | options = { 21 | booleans: true, 22 | evaluate: true, 23 | global_defs: { 24 | A: true, 25 | }, 26 | } 27 | input: { 28 | console.log(A == 1); 29 | } 30 | expect: { 31 | console.log(!0); 32 | } 33 | } 34 | 35 | condition_evaluate: { 36 | options = { 37 | booleans: true, 38 | dead_code: false, 39 | evaluate: true, 40 | loops: false, 41 | } 42 | input: { 43 | while (1 === 2); 44 | for (; 1 == true;); 45 | if (void 0 == null); 46 | } 47 | expect: { 48 | while (0); 49 | for (; 1;); 50 | if (1); 51 | } 52 | } 53 | 54 | if_else_empty: { 55 | options = { 56 | conditionals: true, 57 | } 58 | input: { 59 | if ({} ? a : b); else {} 60 | } 61 | expect: { 62 | ({}), a; 63 | } 64 | } 65 | 66 | label_if_break: { 67 | options = { 68 | conditionals: true, 69 | dead_code: true, 70 | evaluate: true, 71 | side_effects: true, 72 | unused: true, 73 | } 74 | input: { 75 | L: if (true) { 76 | a; 77 | break L; 78 | } 79 | } 80 | expect: { 81 | a; 82 | } 83 | } 84 | 85 | while_if_break: { 86 | options = { 87 | conditionals: true, 88 | loops: true, 89 | sequences: true, 90 | } 91 | input: { 92 | while (a) { 93 | if (b) if(c) d; 94 | if (e) break; 95 | } 96 | } 97 | expect: { 98 | for (; a && (b && c && d, !e);); 99 | } 100 | } 101 | 102 | if_return: { 103 | options = { 104 | booleans: true, 105 | conditionals: true, 106 | if_return: true, 107 | passes: 2, 108 | sequences: true, 109 | side_effects: true, 110 | } 111 | input: { 112 | function f(w, x, y, z) { 113 | if (x) return; 114 | if (w) { 115 | if (y) return; 116 | } else if (z) return; 117 | if (x == y) return true; 118 | 119 | if (x) w(); 120 | if (y) z(); 121 | return true; 122 | } 123 | } 124 | expect: { 125 | function f(w, x, y, z) { 126 | if (!x) { 127 | if (w) { 128 | if (y) return; 129 | } else if (z) return; 130 | return x != y && (x && w(), y) && z(), !0; 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /test/compress/wrap_iife.js: -------------------------------------------------------------------------------- 1 | wrap_iife: { 2 | options = { 3 | negate_iife: false, 4 | } 5 | beautify = { 6 | wrap_iife: true, 7 | } 8 | input: { 9 | (function() { 10 | return function() { 11 | console.log('test') 12 | }; 13 | })()(); 14 | } 15 | expect_exact: '(function(){return function(){console.log("test")}})()();' 16 | } 17 | 18 | wrap_iife_in_expression: { 19 | options = { 20 | negate_iife: false, 21 | } 22 | beautify = { 23 | wrap_iife: true, 24 | } 25 | input: { 26 | foo = (function() { 27 | return bar(); 28 | })(); 29 | } 30 | expect_exact: 'foo=(function(){return bar()})();' 31 | } 32 | 33 | wrap_iife_in_return_call: { 34 | options = { 35 | negate_iife: false, 36 | } 37 | beautify = { 38 | wrap_iife: true, 39 | } 40 | input: { 41 | (function() { 42 | return (function() { 43 | console.log('test') 44 | })(); 45 | })()(); 46 | } 47 | expect_exact: '(function(){return(function(){console.log("test")})()})()();' 48 | } 49 | -------------------------------------------------------------------------------- /test/exports.js: -------------------------------------------------------------------------------- 1 | exports["Compressor"] = Compressor; 2 | exports["defaults"] = defaults; 3 | exports["is_statement"] = is_statement; 4 | exports["JS_Parse_Error"] = JS_Parse_Error; 5 | exports["List"] = List; 6 | exports["mangle_properties"] = mangle_properties; 7 | exports["minify"] = minify; 8 | exports["OutputStream"] = OutputStream; 9 | exports["parse"] = parse; 10 | exports["push_uniq"] = push_uniq; 11 | exports["reserve_quoted_keys"] = reserve_quoted_keys; 12 | exports["string_template"] = string_template; 13 | exports["to_ascii"] = to_ascii; 14 | exports["tokenizer"] = tokenizer; 15 | exports["TreeTransformer"] = TreeTransformer; 16 | exports["TreeWalker"] = TreeWalker; 17 | exports["vlq_decode"] = vlq_decode; 18 | -------------------------------------------------------------------------------- /test/fetch.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var parse = require("url").parse; 3 | var path = require("path"); 4 | 5 | try { 6 | fs.mkdirSync("./tmp"); 7 | } catch (e) { 8 | if (e.code != "EEXIST") throw e; 9 | } 10 | 11 | function local(url) { 12 | return path.join("./tmp", encodeURIComponent(url)); 13 | } 14 | 15 | function read(url) { 16 | return fs.createReadStream(local(url)); 17 | } 18 | 19 | module.exports = function(url, callback) { 20 | var result = read(url); 21 | result.on("error", function(e) { 22 | if (e.code != "ENOENT") return callback(e); 23 | var options = parse(url); 24 | options.rejectUnauthorized = false; 25 | require(options.protocol.slice(0, -1)).get(options, function(res) { 26 | if (res.statusCode !== 200) return callback(res.statusCode); 27 | res.pipe(fs.createWriteStream(local(url))); 28 | callback(null, res); 29 | }); 30 | }).on("open", function() { 31 | callback(null, result); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /test/input/comments/filter.js: -------------------------------------------------------------------------------- 1 | // foo 2 | /*@preserve*/ 3 | // bar 4 | -------------------------------------------------------------------------------- /test/input/enclose/input.js: -------------------------------------------------------------------------------- 1 | function enclose() { 2 | console.log("test enclose"); 3 | } 4 | enclose(); 5 | -------------------------------------------------------------------------------- /test/input/global_defs/nested.js: -------------------------------------------------------------------------------- 1 | console.log(C.V, C.D); 2 | -------------------------------------------------------------------------------- /test/input/global_defs/simple.js: -------------------------------------------------------------------------------- 1 | console.log(D); 2 | -------------------------------------------------------------------------------- /test/input/invalid/assign_1.js: -------------------------------------------------------------------------------- 1 | console.log(1 || 5--); 2 | -------------------------------------------------------------------------------- /test/input/invalid/assign_2.js: -------------------------------------------------------------------------------- 1 | console.log(2 || (Math.random() /= 2)); 2 | -------------------------------------------------------------------------------- /test/input/invalid/assign_3.js: -------------------------------------------------------------------------------- 1 | console.log(3 || ++this); 2 | -------------------------------------------------------------------------------- /test/input/invalid/assign_4.js: -------------------------------------------------------------------------------- 1 | console.log(4 || (null = 4)); 2 | -------------------------------------------------------------------------------- /test/input/invalid/assign_5.js: -------------------------------------------------------------------------------- 1 | console.log(5 || ([]?.length ^= 5)); 2 | -------------------------------------------------------------------------------- /test/input/invalid/delete.js: -------------------------------------------------------------------------------- 1 | function f(x) { 2 | delete 42; 3 | delete (0, x); 4 | delete null; 5 | delete x; 6 | } 7 | 8 | function g(x) { 9 | "use strict"; 10 | delete 42; 11 | delete (0, x); 12 | delete null; 13 | delete x; 14 | } 15 | -------------------------------------------------------------------------------- /test/input/invalid/destructured_var.js: -------------------------------------------------------------------------------- 1 | function f() { 2 | var { eval } = null; 3 | } 4 | 5 | function g() { 6 | "use strict"; 7 | var { eval } = 42; 8 | } 9 | -------------------------------------------------------------------------------- /test/input/invalid/dot_1.js: -------------------------------------------------------------------------------- 1 | a.= 2 | -------------------------------------------------------------------------------- /test/input/invalid/dot_2.js: -------------------------------------------------------------------------------- 1 | %.a; 2 | -------------------------------------------------------------------------------- /test/input/invalid/dot_3.js: -------------------------------------------------------------------------------- 1 | a./(); 2 | -------------------------------------------------------------------------------- /test/input/invalid/else.js: -------------------------------------------------------------------------------- 1 | if (0) else 1; 2 | -------------------------------------------------------------------------------- /test/input/invalid/eof.js: -------------------------------------------------------------------------------- 1 | foo, bar( 2 | -------------------------------------------------------------------------------- /test/input/invalid/for-await.js: -------------------------------------------------------------------------------- 1 | for await (; console.log(42);); 2 | -------------------------------------------------------------------------------- /test/input/invalid/for-in_1.js: -------------------------------------------------------------------------------- 1 | var a, b = [1, 2]; 2 | for (1, 2, a in b) { 3 | console.log(a, b[a]); 4 | } 5 | -------------------------------------------------------------------------------- /test/input/invalid/for-in_2.js: -------------------------------------------------------------------------------- 1 | var c = [1, 2]; 2 | for (var a, b in c) { 3 | console.log(a, c[a]); 4 | } 5 | -------------------------------------------------------------------------------- /test/input/invalid/for-of_1.js: -------------------------------------------------------------------------------- 1 | var a = [ 1 ], b; 2 | for (b = 2 of a) 3 | console.log(b); 4 | -------------------------------------------------------------------------------- /test/input/invalid/for-of_2.js: -------------------------------------------------------------------------------- 1 | var a = [ 1 ]; 2 | for (var b = 2 of a) 3 | console.log(b); 4 | -------------------------------------------------------------------------------- /test/input/invalid/function_1.js: -------------------------------------------------------------------------------- 1 | function f(arguments) { 2 | } 3 | 4 | function g(arguments) { 5 | "use strict"; 6 | } 7 | -------------------------------------------------------------------------------- /test/input/invalid/function_2.js: -------------------------------------------------------------------------------- 1 | function arguments() { 2 | } 3 | 4 | function eval() { 5 | "use strict"; 6 | } 7 | -------------------------------------------------------------------------------- /test/input/invalid/function_3.js: -------------------------------------------------------------------------------- 1 | !function eval() { 2 | }(); 3 | 4 | !function arguments() { 5 | "use strict"; 6 | }(); 7 | -------------------------------------------------------------------------------- /test/input/invalid/loop-no-body.js: -------------------------------------------------------------------------------- 1 | for (var i = 0; i < 1; i++) 2 | -------------------------------------------------------------------------------- /test/input/invalid/object.js: -------------------------------------------------------------------------------- 1 | console.log({%: 1}); 2 | -------------------------------------------------------------------------------- /test/input/invalid/optional-template.js: -------------------------------------------------------------------------------- 1 | console?.log``; 2 | -------------------------------------------------------------------------------- /test/input/invalid/return.js: -------------------------------------------------------------------------------- 1 | return 42; 2 | -------------------------------------------------------------------------------- /test/input/invalid/simple.js: -------------------------------------------------------------------------------- 1 | function f(a{} 2 | -------------------------------------------------------------------------------- /test/input/invalid/switch.js: -------------------------------------------------------------------------------- 1 | switch (0) { 2 | default: 3 | default: 4 | } 5 | -------------------------------------------------------------------------------- /test/input/invalid/tab.js: -------------------------------------------------------------------------------- 1 | foo( xyz, 0abc); 2 | -------------------------------------------------------------------------------- /test/input/invalid/try.js: -------------------------------------------------------------------------------- 1 | function f() { 2 | try {} catch (eval) {} 3 | } 4 | 5 | function g() { 6 | "use strict"; 7 | try {} catch (eval) {} 8 | } 9 | -------------------------------------------------------------------------------- /test/input/invalid/var.js: -------------------------------------------------------------------------------- 1 | function f() { 2 | var eval; 3 | } 4 | 5 | function g() { 6 | "use strict"; 7 | var eval; 8 | } 9 | -------------------------------------------------------------------------------- /test/input/issue-1236/simple.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var foo = function foo(x) { 4 | return "foo " + x; 5 | }; 6 | console.log(foo("bar")); 7 | 8 | //# sourceMappingURL=simple.js.map 9 | -------------------------------------------------------------------------------- /test/input/issue-1236/simple.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": ["index.js"], 4 | "names": [], 5 | "mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ", 6 | "file": "simple.js", 7 | "sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"] 8 | } 9 | -------------------------------------------------------------------------------- /test/input/issue-1242/bar.es5: -------------------------------------------------------------------------------- 1 | function bar(x) { 2 | var triple = x * (2 + 1); 3 | return triple; 4 | } 5 | -------------------------------------------------------------------------------- /test/input/issue-1242/baz.es5: -------------------------------------------------------------------------------- 1 | function baz(x) { 2 | var half = x / 2; 3 | return half; 4 | } 5 | -------------------------------------------------------------------------------- /test/input/issue-1242/foo.es5: -------------------------------------------------------------------------------- 1 | var print = console.log.bind(console); 2 | function foo(x) { 3 | var twice = x * 2; 4 | print('Foo:', twice); 5 | } 6 | -------------------------------------------------------------------------------- /test/input/issue-1242/qux.js: -------------------------------------------------------------------------------- 1 | var x = bar(1+2); 2 | var y = baz(3+9); 3 | print('q' + 'u' + 'x', x, y); 4 | foo(5+6); 5 | -------------------------------------------------------------------------------- /test/input/issue-1323/sample.js: -------------------------------------------------------------------------------- 1 | var bar = (function() { 2 | function foo (bar) { 3 | return bar; 4 | } 5 | 6 | return foo; 7 | })(); -------------------------------------------------------------------------------- /test/input/issue-1431/sample.js: -------------------------------------------------------------------------------- 1 | function f(x) { 2 | return function() { 3 | function n(a) { 4 | return a * a; 5 | } 6 | return x(n); 7 | }; 8 | } 9 | 10 | function g(op) { 11 | return op(1) + op(2); 12 | } 13 | 14 | console.log(f(g)() == 5); -------------------------------------------------------------------------------- /test/input/issue-1482/beautify.js: -------------------------------------------------------------------------------- 1 | if (x) foo(); 2 | 3 | if (x) foo(); else baz(); 4 | 5 | if (x) foo(); else if (y) bar(); else baz(); 6 | 7 | if (x) if (y) foo(); else bar(); else baz(); 8 | 9 | if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); 10 | 11 | function f() { 12 | if (x) foo(); 13 | if (x) foo(); else baz(); 14 | if (x) foo(); else if (y) bar(); else baz(); 15 | if (x) if (y) foo(); else bar(); else baz(); 16 | if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); 17 | } 18 | -------------------------------------------------------------------------------- /test/input/issue-1482/braces.js: -------------------------------------------------------------------------------- 1 | if (x) { 2 | foo(); 3 | } 4 | 5 | if (x) { 6 | foo(); 7 | } else { 8 | baz(); 9 | } 10 | 11 | if (x) { 12 | foo(); 13 | } else if (y) { 14 | bar(); 15 | } else { 16 | baz(); 17 | } 18 | 19 | if (x) { 20 | if (y) { 21 | foo(); 22 | } else { 23 | bar(); 24 | } 25 | } else { 26 | baz(); 27 | } 28 | 29 | if (x) { 30 | foo(); 31 | } else if (y) { 32 | bar(); 33 | } else if (z) { 34 | baz(); 35 | } else { 36 | moo(); 37 | } 38 | 39 | function f() { 40 | if (x) { 41 | foo(); 42 | } 43 | if (x) { 44 | foo(); 45 | } else { 46 | baz(); 47 | } 48 | if (x) { 49 | foo(); 50 | } else if (y) { 51 | bar(); 52 | } else { 53 | baz(); 54 | } 55 | if (x) { 56 | if (y) { 57 | foo(); 58 | } else { 59 | bar(); 60 | } 61 | } else { 62 | baz(); 63 | } 64 | if (x) { 65 | foo(); 66 | } else if (y) { 67 | bar(); 68 | } else if (z) { 69 | baz(); 70 | } else { 71 | moo(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test/input/issue-1482/default.js: -------------------------------------------------------------------------------- 1 | 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();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()} 2 | -------------------------------------------------------------------------------- /test/input/issue-1482/input.js: -------------------------------------------------------------------------------- 1 | if (x) foo(); 2 | if (x) foo(); else baz(); 3 | if (x) foo(); else if (y) bar(); else baz(); 4 | if (x) if (y) foo(); else bar(); else baz(); 5 | if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); 6 | function f() { 7 | if (x) foo(); 8 | if (x) foo(); else baz(); 9 | if (x) foo(); else if (y) bar(); else baz(); 10 | if (x) if (y) foo(); else bar(); else baz(); 11 | if (x) foo(); else if (y) bar(); else if (z) baz(); else moo(); 12 | } 13 | -------------------------------------------------------------------------------- /test/input/issue-1632/^{foo}[bar](baz)+$.js: -------------------------------------------------------------------------------- 1 | console.log(x); -------------------------------------------------------------------------------- /test/input/issue-2082/sample.js: -------------------------------------------------------------------------------- 1 | console.log(x); -------------------------------------------------------------------------------- /test/input/issue-2082/sample.js.map: -------------------------------------------------------------------------------- 1 | {"version": 3,"sources": ["index.js"],"mappings": ";"} 2 | -------------------------------------------------------------------------------- /test/input/issue-2310/input.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | return function() { 3 | console.log("PASS"); 4 | }; 5 | } 6 | 7 | (function() { 8 | var f = foo(); 9 | f(); 10 | })(); 11 | -------------------------------------------------------------------------------- /test/input/issue-3040/expect.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function _toConsumableArray(arr) { 4 | return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); 5 | } 6 | 7 | function _nonIterableSpread() { 8 | throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 9 | } 10 | 11 | function _unsupportedIterableToArray(o, minLen) { 12 | if (!o) return; 13 | if (typeof o === "string") return _arrayLikeToArray(o, minLen); 14 | var n = Object.prototype.toString.call(o).slice(8, -1); 15 | if (n === "Object" && o.constructor) n = o.constructor.name; 16 | if (n === "Map" || n === "Set") return Array.from(n); 17 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); 18 | } 19 | 20 | function _iterableToArray(iter) { 21 | if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); 22 | } 23 | 24 | function _arrayWithoutHoles(arr) { 25 | if (Array.isArray(arr)) return _arrayLikeToArray(arr); 26 | } 27 | 28 | function _arrayLikeToArray(arr, len) { 29 | if (len == null || len > arr.length) len = arr.length; 30 | for (var i = 0, arr2 = new Array(len); i < len; i++) { 31 | arr2[i] = arr[i]; 32 | } 33 | return arr2; 34 | } 35 | 36 | var _require = require("bar"), foo = _require.foo; 37 | 38 | var _require2 = require("world"), hello = _require2.hello; 39 | 40 | foo.x.apply(foo, _toConsumableArray(foo.y(hello.z))); 41 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHtmb299ID0gcmVxdWlyZShcImJhclwiKTtcbmNvbnN0IHtoZWxsb30gPSByZXF1aXJlKFwid29ybGRcIik7XG5cbmZvby54KC4uLmZvby55KGhlbGxvLnopKTtcbiJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiZm9vIiwiaGVsbG8iLCJ4IiwiYXBwbHkiLCJfdG9Db25zdW1hYmxlQXJyYXkiLCJ5IiwieiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7ZUFBY0EsUUFBUSxLQUFELEdBQWRDLE0sU0FBQUE7O0EsZ0JBQ1NELFFBQVEsT0FBRCxHQUFoQkUsUSxVQUFBQTs7QUFFUEQsSUFBSUUsRUFBSkMsTUFBQUgsS0FBR0ksbUJBQU1KLElBQUlLLEVBQUVKLE1BQU1LLENBQVosQ0FBTixDQUFBIn0= 42 | -------------------------------------------------------------------------------- /test/input/issue-3040/input.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } 4 | 5 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } 6 | 7 | function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } 8 | 9 | function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } 10 | 11 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } 12 | 13 | function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } 14 | 15 | var _require = require("bar"), 16 | foo = _require.foo; 17 | 18 | var _require2 = require("world"), 19 | hello = _require2.hello; 20 | 21 | foo.x.apply(foo, _toConsumableArray(foo.y(hello.z))); 22 | 23 | //# sourceMappingURL=input.js.map -------------------------------------------------------------------------------- /test/input/issue-3040/input.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [ 4 | "input.js" 5 | ], 6 | "names": [], 7 | "mappings": ";;;;;;;;;;;;;;eAAc,OAAO,CAAC,KAAD,C;IAAd,G,YAAA,G;;gBACS,OAAO,CAAC,OAAD,C;IAAhB,K,aAAA,K;;AAEP,GAAG,CAAC,CAAJ,OAAA,GAAG,qBAAM,GAAG,CAAC,CAAJ,CAAM,KAAK,CAAC,CAAZ,CAAN,EAAH", 8 | "sourcesContent": [ 9 | "const {foo} = require(\"bar\");\nconst {hello} = require(\"world\");\n\nfoo.x(...foo.y(hello.z));\n" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /test/input/issue-3294/input.js: -------------------------------------------------------------------------------- 1 | var Foo = function Foo(){console.log(1+2);}; new Foo(); 2 | 3 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,DeadBeef 4 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQU0sR0FBRyxHQUFDLEFBQUUsWUFBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBLEFBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDOyJ9 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/input/issue-3294/output.js: -------------------------------------------------------------------------------- 1 | console.log(3); 2 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSxDQUFHIn0= 3 | -------------------------------------------------------------------------------- /test/input/issue-3315/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compress": false, 3 | "mangle": { 4 | "properties": { 5 | "regex": "/^_/" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/input/issue-3315/input.js: -------------------------------------------------------------------------------- 1 | function f() { 2 | "aaaaaaaaaa"; 3 | var o = { 4 | prop: 1, 5 | _int: 2, 6 | }; 7 | return o.prop + o._int; 8 | } 9 | -------------------------------------------------------------------------------- /test/input/issue-3441/input.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 2.4.1 2 | (function() { 3 | console.log('hello'); 4 | 5 | }).call(this); 6 | 7 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1haW4uY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtFQUFBLE9BQU8sQ0FBQyxHQUFSLENBQVksT0FBWjtBQUFBIiwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2cgJ2hlbGxvJ1xuIl19 8 | //# sourceURL=/Users/mohamed/Downloads/main.coffee 9 | -------------------------------------------------------------------------------- /test/input/issue-505/input.js: -------------------------------------------------------------------------------- 1 | function test(callback) { 2 | 'aaaaaaaaaaaaaaaa'; 3 | callback(err, data); 4 | callback(err, data); 5 | } 6 | -------------------------------------------------------------------------------- /test/input/issue-505/output.js: -------------------------------------------------------------------------------- 1 | function test(a){ 2 | "aaaaaaaaaaaaaaaa"; 3 | a(err,data),a(err, 4 | data)} 5 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0E7SEFBS0MsR0FDVjtBQUNBQTtoQkFBU0MsSUFBS0MsSUFBSSxFQUNsQkYsRUFBU0MsSUFBS0MsSUFBSSxDQUN0QiJ9 -------------------------------------------------------------------------------- /test/input/issue-520/input.js: -------------------------------------------------------------------------------- 1 | var Foo = function Foo(){console.log(1+2);}; new Foo(); 2 | 3 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQU0sR0FBRyxHQUFDLEFBQUUsWUFBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBLEFBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDOyJ9 4 | -------------------------------------------------------------------------------- /test/input/issue-520/output.js: -------------------------------------------------------------------------------- 1 | console.log(3); 2 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUEwQkEsUUFBUUMsSUFBSSxDQUFHIn0= 3 | -------------------------------------------------------------------------------- /test/input/module/expect.js: -------------------------------------------------------------------------------- 1 | function n(){return this||arguments[0]+arguments[1]}function o(){return this||arguments[0]+arguments[1]}console.log(n(n(1,3),5)),console.log(o(o(2,4),6)); 2 | -------------------------------------------------------------------------------- /test/input/module/input.js: -------------------------------------------------------------------------------- 1 | console.log(function() { 2 | function sum(...params) { 3 | return this || arguments[0] + arguments[1]; 4 | } 5 | return sum(sum(1, 3), 5); 6 | }()); 7 | console.log(function() { 8 | "use strict"; 9 | function sum(...params) { 10 | return this || arguments[0] + arguments[1]; 11 | } 12 | return sum(sum(2, 4), 6); 13 | }()); -------------------------------------------------------------------------------- /test/input/reduce/destructured_assign.js: -------------------------------------------------------------------------------- 1 | var o = {}; 2 | [ o[1 + .1 + .1] ] = [ 42 ]; 3 | console.log(o[1.2]); 4 | -------------------------------------------------------------------------------- /test/input/reduce/destructured_assign.reduced.js: -------------------------------------------------------------------------------- 1 | // (beautified) 2 | var o = {}; 3 | 4 | [ o[1 + .1 + .1] ] = []; 5 | 6 | console.log(o); 7 | // output: { '1.2000000000000002': undefined } 8 | // 9 | // minify: { '1.2': undefined } 10 | // 11 | // options: { 12 | // "compress": { 13 | // "unsafe_math": true 14 | // }, 15 | // "mangle": false, 16 | // "validate": true 17 | // } -------------------------------------------------------------------------------- /test/input/reduce/destructured_catch.js: -------------------------------------------------------------------------------- 1 | try { 2 | "foo" in 42; 3 | } catch ({ 4 | message, 5 | }) { 6 | console.log(message); 7 | } 8 | -------------------------------------------------------------------------------- /test/input/reduce/destructured_catch.reduced.js: -------------------------------------------------------------------------------- 1 | // (beautified) 2 | try { 3 | 1 in 0; 4 | } catch (message) { 5 | console.log(message); 6 | } 7 | // output: TypeError: Cannot use 'in' operator to search for '1' in 0 8 | // 9 | // minify: TypeError: Cannot use 'in' operator to search for '0' in 0 10 | // 11 | // options: { 12 | // "mangle": false 13 | // } -------------------------------------------------------------------------------- /test/input/reduce/diff_error.js: -------------------------------------------------------------------------------- 1 | console.log(function(undefined) { 2 | return undefined[function() { 3 | {} 4 | }] || 1 + .1 + .1; 5 | }(42)); 6 | -------------------------------------------------------------------------------- /test/input/reduce/diff_error.reduced.js: -------------------------------------------------------------------------------- 1 | // (beautified) 2 | console.log(1 + .1 + .1); 3 | // output: 1.2000000000000002 4 | // 5 | // minify: 1.2 6 | // 7 | // options: { 8 | // "compress": { 9 | // "unsafe_math": true 10 | // }, 11 | // "mangle": false 12 | // } -------------------------------------------------------------------------------- /test/input/reduce/export_default.js: -------------------------------------------------------------------------------- 1 | var unused; 2 | export default class { 3 | ____11111() { 4 | a, b, c, d, e; 5 | f, g, h, i, j; 6 | k, l, m, n, o; 7 | p, q, r, s, t; 8 | u, v, w, x, y, z; 9 | A, B, C, D, E; 10 | F, G, H, I, J; 11 | K, L, M, N, O; 12 | P, Q, R, S, T; 13 | U, V, W, X, Y, Z; 14 | $, _; 15 | unused; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/input/reduce/label.js: -------------------------------------------------------------------------------- 1 | UNUSED: { 2 | console.log(0 - .1 - .1 - .1); 3 | } 4 | -------------------------------------------------------------------------------- /test/input/reduce/label.reduced.js: -------------------------------------------------------------------------------- 1 | // (beautified) 2 | console.log(0 - 1 - .1 - .1); 3 | // output: -1.2000000000000002 4 | // 5 | // minify: -1.2 6 | // 7 | // options: { 8 | // "compress": { 9 | // "unsafe_math": true 10 | // }, 11 | // "mangle": false 12 | // } -------------------------------------------------------------------------------- /test/input/reduce/setter.js: -------------------------------------------------------------------------------- 1 | ({ 2 | set p(v) { 3 | console.log(+v + .1 + .1); 4 | } 5 | }).p = 1; 6 | -------------------------------------------------------------------------------- /test/input/reduce/setter.reduced.js: -------------------------------------------------------------------------------- 1 | // (beautified) 2 | ({ 3 | set p(v) { 4 | console.log(1 + .1 + .1); 5 | } 6 | }).p = 0; 7 | // output: 1.2000000000000002 8 | // 9 | // minify: 1.2 10 | // 11 | // options: { 12 | // "compress": { 13 | // "unsafe_math": true 14 | // }, 15 | // "mangle": false 16 | // } -------------------------------------------------------------------------------- /test/input/reduce/unsafe_math.js: -------------------------------------------------------------------------------- 1 | var _calls_ = 10, a = 100, b = 10, c = 0; 2 | 3 | function f0(b_1, a, undefined_2) { 4 | a++ + ++b; 5 | { 6 | var expr2 = (b + 1 - .1 - .1 - .1 || a || 3).toString(); 7 | L20778: for (var key2 in expr2) { 8 | (c = c + 1) + [ --b + b_1, typeof f0 == "function" && --_calls_ >= 0 && f0(--b + typeof (undefined_2 = 1 === 1 ? a : b), --b + { 9 | c: (c = c + 1) + null 10 | }, a++ + (typeof f0 == "function" && --_calls_ >= 0 && f0(typeof (c = 1 + c, 3 / "a" * ("c" >>> 23..toString()) >= (b_1 && (b_1[(c = c + 1) + a--] = (- -0, 11 | true + {})))), 3, 25))), 1 === 1 ? a : b ]; 12 | } 13 | } 14 | } 15 | 16 | var a_1 = f0([ , 0 ].length === 2); 17 | 18 | console.log(null, a, b, c, Infinity, NaN, undefined); 19 | -------------------------------------------------------------------------------- /test/input/reduce/unsafe_math.reduced.js: -------------------------------------------------------------------------------- 1 | // (beautified) 2 | var expr2 = (0 - 1 - .1 - .1).toString(); 3 | 4 | console.log(expr2); 5 | // output: -1.2000000000000002 6 | // 7 | // minify: -1.2 8 | // 9 | // options: { 10 | // "compress": { 11 | // "unsafe_math": true 12 | // }, 13 | // "mangle": false 14 | // } -------------------------------------------------------------------------------- /test/input/rename/input.js: -------------------------------------------------------------------------------- 1 | function f(x) { 2 | return g(x); 3 | function g(x) { 4 | return x + x; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/mocha.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | 3 | var config = { 4 | timeout: function(limit) { 5 | this.limit = limit + lag; 6 | }, 7 | }; 8 | var lag = +process.env["UGLIFY_GITHUB_LAG"] || 0; 9 | var tasks = []; 10 | var titles = []; 11 | config.timeout(10000); 12 | describe = function(title, fn) { 13 | config = Object.create(config); 14 | titles.push(title); 15 | fn.call(config); 16 | titles.pop(); 17 | config = Object.getPrototypeOf(config); 18 | }; 19 | it = function(title, fn) { 20 | fn.limit = config.limit; 21 | fn.titles = titles.slice(); 22 | fn.titles.push(title); 23 | tasks.push(fn); 24 | }; 25 | (function(arg) { 26 | return arg ? [ arg ] : fs.readdirSync("test/mocha").filter(function(file) { 27 | return /\.js$/.test(file); 28 | }); 29 | })(process.argv[2]).forEach(function(file) { 30 | require("./mocha/" + file); 31 | }); 32 | 33 | function log_titles(log, current, marker) { 34 | var indent = ""; 35 | var writing = false; 36 | for (var i = 0; i < current.length; i++, indent += " ") { 37 | if (titles[i] != current[i]) writing = true; 38 | if (writing) log(indent + (i == current.length - 1 && marker || "") + current[i]); 39 | } 40 | titles = current; 41 | } 42 | 43 | function red(text) { 44 | return "\u001B[31m" + text + "\u001B[39m"; 45 | } 46 | 47 | function green(text) { 48 | return "\u001B[32m" + text + "\u001B[39m"; 49 | } 50 | 51 | var errors = []; 52 | var total = tasks.length; 53 | titles = []; 54 | process.nextTick(function run() { 55 | var task = tasks.shift(); 56 | if (task) try { 57 | var elapsed = Date.now(); 58 | var timer; 59 | var done = function() { 60 | elapsed = Date.now() - elapsed; 61 | if (elapsed > task.limit) { 62 | throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms"); 63 | } 64 | reset(); 65 | log_titles(console.log, task.titles, green('\u221A ')); 66 | process.nextTick(run); 67 | }; 68 | if (task.length) { 69 | task.timeout = function(limit) { 70 | clearTimeout(timer); 71 | limit += lag; 72 | task.limit = limit; 73 | timer = setTimeout(function() { 74 | raise(new Error("Timed out: exceeds " + limit + "ms")); 75 | }, limit); 76 | }; 77 | task.timeout(task.limit - lag); 78 | process.on("uncaughtException", raise); 79 | task.call(task, done); 80 | } else { 81 | task.timeout = config.timeout; 82 | task.call(task); 83 | done(); 84 | } 85 | } catch (err) { 86 | raise(err); 87 | } else if (errors.length) { 88 | console.error(); 89 | console.log(red(errors.length + " test(s) failed!")); 90 | titles = []; 91 | errors.forEach(function(titles, index) { 92 | console.error(); 93 | log_titles(console.error, titles, (index + 1) + ") "); 94 | var lines = titles.error.stack.split('\n'); 95 | console.error(red(lines[0])); 96 | console.error(lines.slice(1).join("\n")); 97 | }); 98 | process.exit(1); 99 | } else { 100 | console.log(); 101 | console.log(green(total + " test(s) passed.")); 102 | } 103 | 104 | function raise(err) { 105 | reset(); 106 | task.titles.error = err; 107 | errors.push(task.titles); 108 | log_titles(console.log, task.titles, red('\u00D7 ')); 109 | process.nextTick(run); 110 | } 111 | 112 | function reset() { 113 | clearTimeout(timer); 114 | done = function() {}; 115 | process.removeListener("uncaughtException", raise); 116 | } 117 | }); 118 | -------------------------------------------------------------------------------- /test/mocha/arguments.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../.."); 3 | 4 | describe("arguments", function() { 5 | it("Should known that arguments in functions are local scoped", function() { 6 | var ast = UglifyJS.parse("var arguments; var f = function() {arguments.length}"); 7 | ast.figure_out_scope(); 8 | // Test scope of `var arguments` 9 | assert.strictEqual(ast.find_variable("arguments").global, true); 10 | // Select arguments symbol in function 11 | var symbol = ast.body[1].definitions[0].value.find_variable("arguments"); 12 | assert.strictEqual(symbol.global, false); 13 | assert.strictEqual(symbol.scope, ast. // From ast 14 | body[1]. // Select 2nd statement (equals to `var f ...`) 15 | definitions[0]. // First definition of selected statement 16 | value // Select function as scope 17 | ); 18 | }); 19 | 20 | it("Should recognize when a function uses arguments", function() { 21 | var ast = UglifyJS.parse("function a(){function b(){function c(){}; return arguments[0];}}"); 22 | ast.figure_out_scope(); 23 | assert.strictEqual(ast.body[0].uses_arguments, false); 24 | assert.strictEqual(ast.body[0].body[0].uses_arguments, true); 25 | assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/mocha/awaits.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("async", function() { 5 | it("Should reject `await` as symbol name within async functions only", function() { 6 | [ 7 | "function await() {}", 8 | "function(await) {}", 9 | "function() { await; }", 10 | "function() { await: {} }", 11 | "function() { var await; }", 12 | "function() { function await() {} }", 13 | "function() { try {} catch (await) {} }", 14 | ].forEach(function(code) { 15 | var ast = UglifyJS.parse("(" + code + ")();"); 16 | assert.strictEqual(ast.TYPE, "Toplevel"); 17 | assert.strictEqual(ast.body.length, 1); 18 | assert.strictEqual(ast.body[0].TYPE, "SimpleStatement"); 19 | assert.strictEqual(ast.body[0].body.TYPE, "Call"); 20 | assert.strictEqual(ast.body[0].body.expression.TYPE, "Function"); 21 | assert.throws(function() { 22 | UglifyJS.parse("(async " + code + ")();"); 23 | }, function(e) { 24 | return e instanceof UglifyJS.JS_Parse_Error; 25 | }, code); 26 | }); 27 | }); 28 | it("Should reject `await` expression outside of async functions", function() { 29 | [ 30 | "await 42;", 31 | "function f() { await 42; }", 32 | "async function f() { function g() { await 42; } }", 33 | ].forEach(function(code) { 34 | assert.throws(function() { 35 | UglifyJS.parse(code); 36 | }, function(e) { 37 | return e instanceof UglifyJS.JS_Parse_Error; 38 | }, code); 39 | }); 40 | }); 41 | it("Should reject `await` expression directly on computed key of function argument", function() { 42 | [ 43 | "function f({ [await 42]: a }) {}", 44 | "async function f({ [await 42]: a }) {}", 45 | ].forEach(function(code) { 46 | assert.throws(function() { 47 | UglifyJS.parse(code); 48 | }, function(e) { 49 | return e instanceof UglifyJS.JS_Parse_Error; 50 | }, code); 51 | }); 52 | }); 53 | it("Should accept `await` expression nested within computed key of function argument", function() { 54 | [ 55 | "function f({ [async function() { await 42; }()]: a }) {}", 56 | "async function f({ [async function() { await 42; }()]: a }) {}", 57 | ].forEach(function(code) { 58 | var ast = UglifyJS.parse(code); 59 | assert.strictEqual(ast.TYPE, "Toplevel"); 60 | assert.strictEqual(ast.body.length, 1); 61 | assert.strictEqual(ast.body[0].argnames.length, 1); 62 | assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject"); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/mocha/bug-report.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var exec = require("child_process").exec; 3 | 4 | describe("UGLIFY_BUG_REPORT", function() { 5 | var env = Object.create(process.env); 6 | env.UGLIFY_BUG_REPORT = 1; 7 | it("Should generate bug report via API", function(done) { 8 | exec('"' + process.argv[0] + '"', { env: env }, function(err, stdout) { 9 | if (err) throw err; 10 | assert.strictEqual(stdout, [ 11 | "// UGLIFY_BUG_REPORT", 12 | "// <>", 13 | "", 14 | "//-------------------------------------------------------------", 15 | "// INPUT CODE", 16 | "...---...", 17 | "", 18 | ].join("\n")); 19 | done(); 20 | }).stdin.end('console.log(require("./").minify("...---...").code);'); 21 | }); 22 | it("Should generate bug report via CLI", function(done) { 23 | exec('"' + process.argv[0] + '" bin/uglifyjs -mc', { env: env }, function(err, stdout) { 24 | if (err) throw err; 25 | assert.strictEqual(stdout, [ 26 | "// UGLIFY_BUG_REPORT", 27 | "// {", 28 | '// "mangle": {},', 29 | '// "compress": {}', 30 | "// }", 31 | "", 32 | "//-------------------------------------------------------------", 33 | "// STDIN", 34 | "...---...", 35 | "", 36 | ].join("\n")); 37 | done(); 38 | }).stdin.end("...---..."); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/mocha/getter-setter.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("Getters and setters", function() { 5 | it("Should not accept operator symbols as getter/setter name", function() { 6 | [ 7 | "++", 8 | "--", 9 | "+", 10 | "-", 11 | "!", 12 | "~", 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 | ].reduce(function(tests, illegalOperator) { 46 | tests.push({ 47 | code: "var obj = { get " + illegalOperator + "() { return test; }};", 48 | operator: illegalOperator, 49 | }); 50 | tests.push({ 51 | code: "var obj = { set " + illegalOperator + "(value) { test = value; }};", 52 | operator: illegalOperator, 53 | }); 54 | return tests; 55 | }, []).forEach(function(test) { 56 | assert.throws(function() { 57 | UglifyJS.parse(test.code); 58 | }, test.operator == "=" ? function(e) { 59 | return e instanceof UglifyJS.JS_Parse_Error 60 | && /^Unexpected token: punc «{», expected: punc «.*?»$/.test(e.message); 61 | } : function(e) { 62 | return e instanceof UglifyJS.JS_Parse_Error 63 | && e.message === "Unexpected token: operator «" + test.operator + "»"; 64 | }, "Expected but didn't get a syntax error while parsing following line:\n" + test.code); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/mocha/glob.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var exec = require("child_process").exec; 3 | var path = require("path"); 4 | 5 | describe("bin/uglifyjs with input file globs", function() { 6 | var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs'; 7 | it("bin/uglifyjs with one input file extension glob.", function(done) { 8 | var command = [ 9 | uglifyjscmd, 10 | '"test/input/issue-1242/foo.*"', 11 | "--compress", 12 | "--mangle", 13 | "--no-module", 14 | ].join(" "); 15 | exec(command, function(err, stdout) { 16 | if (err) throw err; 17 | assert.strictEqual(stdout, 'var print=console.log.bind(console);function foo(o){print("Foo:",2*o)}\n'); 18 | done(); 19 | }); 20 | }); 21 | it("bin/uglifyjs with one input file name glob.", function(done) { 22 | var command = [ 23 | uglifyjscmd, 24 | '"test/input/issue-1242/b*.es5"', 25 | "--compress", 26 | "--mangle", 27 | "--no-module", 28 | ].join(" "); 29 | exec(command, function(err, stdout) { 30 | if (err) throw err; 31 | assert.strictEqual(stdout, 'function bar(n){return 3*n}function baz(n){return n/2}\n'); 32 | done(); 33 | }); 34 | }); 35 | it("bin/uglifyjs with multiple input file globs.", function(done) { 36 | var command = [ 37 | uglifyjscmd, 38 | '"test/input/issue-1242/???.es5"', 39 | '"test/input/issue-1242/*.js"', 40 | "--compress", "toplevel,passes=3", 41 | "--mangle", 42 | "--no-module", 43 | ].join(" "); 44 | exec(command, function(err, stdout) { 45 | if (err) throw err; 46 | assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n'); 47 | done(); 48 | }); 49 | }); 50 | it("Should throw with non-matching glob string", function(done) { 51 | var command = uglifyjscmd + ' "test/input/issue-1242/blah.*"'; 52 | 53 | exec(command, function(err, stdout, stderr) { 54 | assert.ok(err); 55 | assert.ok(/^ERROR: ENOENT/.test(stderr)); 56 | done(); 57 | }); 58 | }); 59 | it('"?" in glob string should not match "/"', function(done) { 60 | var command = uglifyjscmd + ' "test/input?issue-1242/foo.*"'; 61 | 62 | exec(command, function(err, stdout, stderr) { 63 | assert.ok(err); 64 | assert.ok(/^ERROR: ENOENT/.test(stderr)); 65 | done(); 66 | }); 67 | }); 68 | it("Should handle special characters in glob string", function(done) { 69 | var command = uglifyjscmd + ' "test/input/issue-1632/^{*}[???](*)+$.??" -cm'; 70 | 71 | exec(command, function(err, stdout) { 72 | if (err) throw err; 73 | 74 | assert.strictEqual(stdout, "console.log(x);\n"); 75 | done(); 76 | }); 77 | }); 78 | it("Should handle array of glob strings - matching and otherwise", function(done) { 79 | var dir = "test/input/issue-1242"; 80 | var command = uglifyjscmd + ' "' + [ 81 | path.join(dir, "b*.es5"), 82 | path.join(dir, "z*.es5"), 83 | path.join(dir, "*.js") 84 | ].join('" "') + '"'; 85 | 86 | exec(command, function(err, stdout, stderr) { 87 | assert.ok(err); 88 | assert.ok(/^ERROR: ENOENT.*?z\*\.es5/.test(stderr)); 89 | done(); 90 | }); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /test/mocha/let.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("let", function() { 5 | this.timeout(30000); 6 | it("Should not produce reserved keywords as variable name in mangle", function() { 7 | // Produce a lot of variables in a function and run it through mangle. 8 | var s = '"dddddeeeeelllllooooottttt"; function foo() {'; 9 | for (var i = 0; i < 18000; i++) { 10 | s += "var v" + i + "=[];"; 11 | } 12 | s += '}'; 13 | var result = UglifyJS.minify(s, { 14 | compress: false, 15 | }); 16 | if (result.error) throw result.error; 17 | // Verify that select keywords and reserved keywords not produced 18 | [ 19 | "do", 20 | "let", 21 | "var", 22 | ].forEach(function(name) { 23 | assert.strictEqual(result.code.indexOf("var " + name + "="), -1); 24 | }); 25 | // Verify that the variable names that appeared immediately before 26 | // and after the erroneously generated variable name still exist 27 | // to show the test generated enough symbols. 28 | [ 29 | "to", "eo", 30 | "eet", "fet", 31 | "rar", "oar", 32 | ].forEach(function(name) { 33 | assert.notStrictEqual(result.code.indexOf("var " + name + "="), -1); 34 | }); 35 | }); 36 | it("Should quote mangled properties that are reserved keywords", function() { 37 | var s = '"rrrrrnnnnniiiiiaaaaa";'; 38 | for (var i = 0; i < 18000; i++) { 39 | s += "v.b" + i + "=v;"; 40 | } 41 | var result = UglifyJS.minify(s, { 42 | compress: false, 43 | ie: true, 44 | mangle: { 45 | properties: { 46 | domprops: true, 47 | }, 48 | }, 49 | }); 50 | if (result.error) throw result.error; 51 | [ 52 | "in", 53 | "var", 54 | ].forEach(function(name) { 55 | assert.notStrictEqual(result.code.indexOf('v["' + name + '"]'), -1); 56 | }); 57 | }); 58 | it("Should parse `let` as name correctly", function() { 59 | [ 60 | "for(var let;let;let)let;", 61 | "function let(let){let}", 62 | ].forEach(function(code) { 63 | var ast = UglifyJS.parse(code); 64 | assert.strictEqual(ast.print_to_string(), code); 65 | assert.throws(function() { 66 | UglifyJS.parse('"use strict";' + code); 67 | }, function(e) { 68 | return e instanceof UglifyJS.JS_Parse_Error && e.message == "Unexpected let in strict mode"; 69 | }, code); 70 | }); 71 | }); 72 | it("Should throw on ambiguous use of `let`", function() { 73 | [ 74 | "export let", 75 | [ 76 | "let", 77 | "console.log(42)", 78 | ].join("\n"), 79 | [ 80 | "let", 81 | "[ console.log(42) ]", 82 | ].join("\n"), 83 | [ 84 | "let", 85 | "{", 86 | " console.log(42)", 87 | "}", 88 | ].join("\n"), 89 | ].forEach(function(code) { 90 | assert.throws(function() { 91 | UglifyJS.parse(code); 92 | }, function(e) { 93 | return e instanceof UglifyJS.JS_Parse_Error; 94 | }, code); 95 | }); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /test/mocha/line-endings.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("line-endings", function() { 5 | var options = { 6 | compress: false, 7 | mangle: false, 8 | output: { 9 | beautify: false, 10 | comments: /^!/, 11 | } 12 | }; 13 | var expected_code = '/*!one\n2\n3*/\nfunction f(x){if(x)return 3}'; 14 | 15 | it("Should parse LF line endings", function() { 16 | var js = '/*!one\n2\n3*///comment\nfunction f(x) {\n if (x)\n//comment\n return 3;\n}\n'; 17 | var result = UglifyJS.minify(js, options); 18 | assert.strictEqual(result.code, expected_code); 19 | }); 20 | 21 | it("Should parse CR/LF line endings", function() { 22 | 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'; 23 | var result = UglifyJS.minify(js, options); 24 | assert.strictEqual(result.code, expected_code); 25 | }); 26 | 27 | it("Should parse CR line endings", function() { 28 | var js = '/*!one\r2\r3*///comment\rfunction f(x) {\r if (x)\r//comment\r return 3;\r}\r'; 29 | var result = UglifyJS.minify(js, options); 30 | assert.strictEqual(result.code, expected_code); 31 | }); 32 | 33 | it("Should not allow line terminators in regexp", function() { 34 | var inputs = [ 35 | "/\n/", 36 | "/\r/", 37 | "/\u2028/", 38 | "/\u2029/", 39 | "/\\\n/", 40 | "/\\\r/", 41 | "/\\\u2028/", 42 | "/\\\u2029/", 43 | "/someRandomTextLike[]()*AndThen\n/" 44 | ] 45 | var test = function(input) { 46 | return function() { 47 | UglifyJS.parse(input); 48 | } 49 | } 50 | var fail = function(e) { 51 | return e instanceof UglifyJS.JS_Parse_Error 52 | && e.message === "Unexpected line terminator"; 53 | } 54 | for (var i = 0; i < inputs.length; i++) { 55 | assert.throws(test(inputs[i]), fail); 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/mocha/minify-file-map.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../.."); 3 | 4 | describe("Input file as map", function() { 5 | it("Should accept object", function() { 6 | var jsMap = { 7 | '/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};' 8 | }; 9 | var result = UglifyJS.minify(jsMap, { 10 | sourceMap: true, 11 | }); 12 | if (result.error) throw result.error; 13 | var map = JSON.parse(result.map); 14 | assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); 15 | assert.deepEqual(map.sources, ['/scripts/foo.js']); 16 | assert.strictEqual(map.file, undefined); 17 | 18 | result = UglifyJS.minify(jsMap); 19 | assert.strictEqual(result.map, undefined); 20 | 21 | result = UglifyJS.minify(jsMap, {sourceMap: {filename: 'out.js'}}); 22 | map = JSON.parse(result.map); 23 | assert.strictEqual(map.file, 'out.js'); 24 | }); 25 | 26 | it("Should accept array of strings", function() { 27 | var jsSeq = [ 28 | 'var foo = {"x": 1, y: 2, \'z\': 3};', 29 | 'var bar = 15;' 30 | ]; 31 | var result = UglifyJS.minify(jsSeq, { 32 | sourceMap: true, 33 | }); 34 | if (result.error) throw result.error; 35 | var map = JSON.parse(result.map); 36 | assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;'); 37 | assert.deepEqual(map.sources, ['0', '1']); 38 | }); 39 | 40 | it("Should correctly include source", function() { 41 | var jsMap = { 42 | '/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};' 43 | }; 44 | var result = UglifyJS.minify(jsMap, { 45 | sourceMap: { 46 | includeSources: true, 47 | }, 48 | }); 49 | if (result.error) throw result.error; 50 | var map = JSON.parse(result.map); 51 | assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};'); 52 | assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};']); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/mocha/number-literal.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("Number literals", function() { 5 | it("Should allow legacy octal literals in non-strict mode", function() { 6 | [ 7 | "'use strict'\n.slice()\n00", 8 | '"use strict"\n.slice()\nvar foo = 00', 9 | ].forEach(function(input) { 10 | UglifyJS.parse(input); 11 | }); 12 | }); 13 | it("Should not allow legacy octal literals in strict mode", function() { 14 | var inputs = [ 15 | '"use strict";00;', 16 | '"use strict"; var foo = 00;', 17 | ]; 18 | var test = function(input) { 19 | return function() { 20 | UglifyJS.parse(input); 21 | } 22 | }; 23 | var error = function(e) { 24 | return e instanceof UglifyJS.JS_Parse_Error 25 | && e.message === "Legacy octal literals are not allowed in strict mode"; 26 | }; 27 | for (var i = 0; i < inputs.length; i++) { 28 | assert.throws(test(inputs[i]), error, inputs[i]); 29 | } 30 | }); 31 | it("Should parse binary, hexadecimal, octal and underscore correctly", function() { 32 | [ 33 | "42", 34 | "4_2", 35 | "052", 36 | "0o52", 37 | "0O52", 38 | "0o5_2", 39 | "0x2a", 40 | "0X2A", 41 | "0x2_a", 42 | "0b101010", 43 | "0B101010", 44 | "0b101_010", 45 | "0.0000000042e+10", 46 | "0.0000000042E+10", 47 | "0.0_000000042e+10", 48 | "0.0000000042e+1_0", 49 | "0.000_000_004_2e+1_0", 50 | "0.000_000_004_2e+1_0-0B101_010+0x2_A-0o5_2+4_2", 51 | ].forEach(function(code) { 52 | var result = UglifyJS.minify(code, { 53 | expression: true, 54 | }); 55 | if (result.error) throw result.error; 56 | assert.strictEqual(result.code, "42"); 57 | }); 58 | }); 59 | it("Should reject invalid use of underscore", function() { 60 | [ 61 | "_42", 62 | "_+42", 63 | "+_42", 64 | ].forEach(function(code) { 65 | var node = UglifyJS.parse(code, { 66 | expression: true, 67 | }); 68 | assert.ok(!node.is_constant(), code); 69 | assert.ok(!(node instanceof UglifyJS.AST_Statement), code); 70 | }); 71 | [ 72 | "42_", 73 | "4__2", 74 | "0_52", 75 | "05_2", 76 | "0_o52", 77 | "0o_52", 78 | "0.0000000042_e10", 79 | "0.0000000042e_10", 80 | "0.0000000042e_+10", 81 | "0.0000000042e+_10", 82 | ].forEach(function(code) { 83 | assert.throws(function() { 84 | UglifyJS.parse(code); 85 | }, function(e) { 86 | return e instanceof UglifyJS.JS_Parse_Error; 87 | }, code); 88 | }); 89 | }); 90 | it("Should reject invalid syntax under expression=true", function() { 91 | assert.throws(function() { 92 | UglifyJS.parse("42.g", { 93 | expression: true, 94 | }); 95 | }, function(e) { 96 | return e instanceof UglifyJS.JS_Parse_Error; 97 | }); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /test/mocha/parentheses.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../.."); 3 | 4 | describe("parentheses", function() { 5 | it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() { 6 | var tests = [ 7 | "new x(1);", 8 | "new x;", 9 | "new new x;", 10 | "new (function(foo){this.foo=foo;})(1);", 11 | "new (function(foo){this.foo=foo;})();", 12 | "new (function test(foo){this.foo=foo;})(1);", 13 | "new (function test(foo){this.foo=foo;})();", 14 | "new true;", 15 | "new (0);", 16 | "new (!0);", 17 | "new (bar = function(foo) {this.foo=foo;})(123);", 18 | "new (bar = function(foo) {this.foo=foo;})();" 19 | ]; 20 | var expected = [ 21 | "new x(1);", 22 | "new x();", 23 | "new new x()();", 24 | "new function(foo) {\n this.foo = foo;\n}(1);", 25 | "new function(foo) {\n this.foo = foo;\n}();", 26 | "new function test(foo) {\n this.foo = foo;\n}(1);", 27 | "new function test(foo) {\n this.foo = foo;\n}();", 28 | "new true();", 29 | "new 0();", 30 | "new (!0)();", 31 | "new (bar = function(foo) {\n this.foo = foo;\n})(123);", 32 | "new (bar = function(foo) {\n this.foo = foo;\n})();" 33 | ]; 34 | for (var i = 0; i < tests.length; i++) { 35 | assert.strictEqual( 36 | UglifyJS.minify(tests[i], { 37 | output: {beautify: true}, 38 | compress: false, 39 | mangle: false 40 | }).code, 41 | expected[i] 42 | ); 43 | } 44 | }); 45 | 46 | it("Should not add trailing parentheses for new expressions with zero arguments in non-beautify mode", function() { 47 | var tests = [ 48 | "new x(1);", 49 | "new x;", 50 | "new new x;", 51 | "new (function(foo){this.foo=foo;})(1);", 52 | "new (function(foo){this.foo=foo;})();", 53 | "new (function test(foo){this.foo=foo;})(1);", 54 | "new (function test(foo){this.foo=foo;})();", 55 | "new true;", 56 | "new (0);", 57 | "new (!0);", 58 | "new (bar = function(foo) {this.foo=foo;})(123);", 59 | "new (bar = function(foo) {this.foo=foo;})();" 60 | ]; 61 | var expected = [ 62 | "new x(1);", 63 | "new x;", 64 | "new(new x);", 65 | "new function(foo){this.foo=foo}(1);", 66 | "new function(foo){this.foo=foo};", 67 | "new function test(foo){this.foo=foo}(1);", 68 | "new function test(foo){this.foo=foo};", 69 | "new true;", 70 | "new 0;", 71 | "new(!0);", 72 | "new(bar=function(foo){this.foo=foo})(123);", 73 | "new(bar=function(foo){this.foo=foo});" 74 | ]; 75 | for (var i = 0; i < tests.length; i++) { 76 | assert.strictEqual( 77 | UglifyJS.minify(tests[i], { 78 | output: {beautify: false}, 79 | compress: false, 80 | mangle: false 81 | }).code, 82 | expected[i] 83 | ); 84 | } 85 | }); 86 | 87 | it("Should compress leading parentheses with reasonable performance", function() { 88 | this.timeout(30000); 89 | var code = [ 90 | "({}?0:1)&&x();", 91 | "(function(){}).name;", 92 | ]; 93 | for (var i = 16; --i >= 0;) { 94 | code = code.concat(code); 95 | } 96 | code = code.join(""); 97 | var result = UglifyJS.minify(code, { 98 | compress: false, 99 | mangle: false, 100 | }); 101 | if (result.error) throw result.error; 102 | // Dismal performance for `assert.strictEqual()` in Node.js 6 103 | assert.ok(result.code === code); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /test/mocha/templates.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var run_code = require("../sandbox").run_code; 3 | var semver = require("semver"); 4 | var UglifyJS = require("../node"); 5 | 6 | describe("Template literals", function() { 7 | it("Should reject invalid literal", function() { 8 | [ 9 | "`foo\\`", 10 | "`foo${bar`", 11 | "`foo${bar}", 12 | ].forEach(function(input) { 13 | assert.throws(function() { 14 | UglifyJS.parse(input); 15 | }, function(e) { 16 | return e instanceof UglifyJS.JS_Parse_Error 17 | && e.message === "Unterminated template literal"; 18 | }, input); 19 | }); 20 | }); 21 | it("Should reject invalid expression", function() { 22 | [ 23 | "`foo${bar;}`", 24 | "`foo${42bar}`", 25 | ].forEach(function(input) { 26 | assert.throws(function() { 27 | UglifyJS.parse(input); 28 | }, function(e) { 29 | return e instanceof UglifyJS.JS_Parse_Error; 30 | }, input); 31 | }); 32 | }); 33 | it("Should process line-break characters correctly", function() { 34 | [ 35 | // native line breaks 36 | [ "`foo\nbar`", "`foo\nbar`" ], 37 | [ "`foo\rbar`", "`foo\nbar`" ], 38 | [ "`foo\r\nbar`", "`foo\nbar`" ], 39 | [ "`foo\r\n\rbar`", "`foo\n\nbar`" ], 40 | // escaped line breaks 41 | [ "`foo\\nbar`", "`foo\\nbar`" ], 42 | [ "`foo\\rbar`", "`foo\\rbar`" ], 43 | [ "`foo\r\\nbar`", "`foo\n\\nbar`" ], 44 | [ "`foo\\r\nbar`", "`foo\\r\nbar`" ], 45 | [ "`foo\\r\\nbar`", "`foo\\r\\nbar`" ], 46 | // continuation 47 | [ "`foo\\\nbar`", "`foo\\\nbar`" ], 48 | [ "`foo\\\rbar`", "`foo\\\nbar`" ], 49 | [ "`foo\\\r\nbar`", "`foo\\\nbar`" ], 50 | [ "`foo\\\r\n\rbar`", "`foo\\\n\nbar`" ], 51 | [ "`foo\\\\nbar`", "`foo\\\\nbar`" ], 52 | [ "`foo\\\\rbar`", "`foo\\\\rbar`" ], 53 | [ "`foo\\\\r\nbar`", "`foo\\\\r\nbar`" ], 54 | ].forEach(function(test) { 55 | var input = "console.log(" + test[0] + ");"; 56 | var result = UglifyJS.minify(input, { 57 | compress: false, 58 | mangle: false, 59 | }); 60 | if (result.error) throw result.error; 61 | var expected = "console.log(" + test[1] + ");"; 62 | assert.strictEqual(result.code, expected, test[0]); 63 | if (semver.satisfies(process.version, "<4")) return; 64 | assert.strictEqual(run_code(result.code), run_code(input), test[0]); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/mocha/tokens.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../.."); 3 | 4 | describe("tokens", function() { 5 | it("Should give correct positions for accessors", function() { 6 | // location 0 1 2 3 4 7 | // 01234567890123456789012345678901234567890123456789 8 | var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }"); 9 | // test all AST_ObjectProperty tokens are set as expected 10 | var found = false; 11 | ast.walk(new UglifyJS.TreeWalker(function(node) { 12 | if (node instanceof UglifyJS.AST_ObjectProperty) { 13 | found = true; 14 | assert.equal(node.start.pos, 12); 15 | assert.equal(node.end.endpos, 46); 16 | assert(node.key instanceof UglifyJS.AST_SymbolRef); 17 | assert.equal(node.key.start.pos, 17); 18 | assert.equal(node.key.end.endpos, 21); 19 | assert(node.value instanceof UglifyJS.AST_Accessor); 20 | assert.equal(node.value.start.pos, 22); 21 | assert.equal(node.value.end.endpos, 46); 22 | } 23 | })); 24 | assert(found, "AST_ObjectProperty not found"); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/mocha/with.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("With", function() { 5 | it("Should throw syntaxError when using with statement in strict mode", function() { 6 | var code = '"use strict";\nthrow NotEarlyError;\nwith ({}) { }'; 7 | var test = function() { 8 | UglifyJS.parse(code); 9 | } 10 | var error = function(e) { 11 | return e instanceof UglifyJS.JS_Parse_Error 12 | && e.message === "Strict mode may not include a with statement"; 13 | } 14 | assert.throws(test, error); 15 | }); 16 | it("Should set uses_with for scopes involving With statements", function() { 17 | var ast = UglifyJS.parse("with(e) {f(1, 2)}"); 18 | ast.figure_out_scope(); 19 | assert.equal(ast.uses_with, true); 20 | assert.equal(ast.body[0].expression.scope.resolve().uses_with, true); 21 | assert.equal(ast.body[0].body.body[0].body.expression.scope.resolve().uses_with, true); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/mocha/yields.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var UglifyJS = require("../node"); 3 | 4 | describe("generator", function() { 5 | it("Should reject `yield` as symbol name within generator functions only", function() { 6 | [ 7 | "function yield() {}", 8 | "function(yield) {}", 9 | "function() { yield: {} }", 10 | "function() { var yield; }", 11 | "function() { function yield() {} }", 12 | "function() { try {} catch (yield) {} }", 13 | ].forEach(function(code) { 14 | var ast = UglifyJS.parse("(" + code + ")();"); 15 | assert.strictEqual(ast.TYPE, "Toplevel"); 16 | assert.strictEqual(ast.body.length, 1); 17 | assert.strictEqual(ast.body[0].TYPE, "SimpleStatement"); 18 | assert.strictEqual(ast.body[0].body.TYPE, "Call"); 19 | assert.strictEqual(ast.body[0].body.expression.TYPE, "Function"); 20 | assert.throws(function() { 21 | UglifyJS.parse("(" + code.replace(/^function/, "function*") + ")();"); 22 | }, function(e) { 23 | return e instanceof UglifyJS.JS_Parse_Error; 24 | }, code); 25 | }); 26 | }); 27 | it("Should reject `yield` expression outside of generator functions", function() { 28 | [ 29 | "yield 42;", 30 | "function f() { yield 42; }", 31 | "function* f() { function g() { yield 42; } }", 32 | ].forEach(function(code) { 33 | assert.throws(function() { 34 | UglifyJS.parse(code); 35 | }, function(e) { 36 | return e instanceof UglifyJS.JS_Parse_Error; 37 | }, code); 38 | }); 39 | }); 40 | it("Should reject `yield` expression directly on computed key of function argument", function() { 41 | [ 42 | "function f({ [yield 42]: a }) {}", 43 | "function* f({ [yield 42]: a }) {}", 44 | ].forEach(function(code) { 45 | assert.throws(function() { 46 | UglifyJS.parse(code); 47 | }, function(e) { 48 | return e instanceof UglifyJS.JS_Parse_Error; 49 | }, code); 50 | }); 51 | }); 52 | it("Should accept `yield` expression nested within computed key of function argument", function() { 53 | [ 54 | "function f({ [function*() { yield 42; }()]: a }) {}", 55 | "function* f({ [function*() { yield 42; }()]: a }) {}", 56 | ].forEach(function(code) { 57 | var ast = UglifyJS.parse(code); 58 | assert.strictEqual(ast.TYPE, "Toplevel"); 59 | assert.strictEqual(ast.body.length, 1); 60 | assert.strictEqual(ast.body[0].argnames.length, 1); 61 | assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject"); 62 | }); 63 | }); 64 | it("Should reject `yield*` without an expression", function() { 65 | [ 66 | "yield*", 67 | "yield*;", 68 | "yield*,", 69 | "(yield*)", 70 | "[ yield* ]", 71 | "42[yield*]", 72 | "yield* && 42", 73 | ].forEach(function(code) { 74 | code = "function* f() { " + code + " }"; 75 | assert.throws(function() { 76 | UglifyJS.parse(code); 77 | }, function(e) { 78 | return e instanceof UglifyJS.JS_Parse_Error; 79 | }, code); 80 | }); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/node.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | 3 | new Function("domprops", "exports", require("../tools/node").FILES.map(function(file) { 4 | if (/exports\.js$/.test(file)) file = require.resolve("./exports"); 5 | return fs.readFileSync(file, "utf8"); 6 | }).join("\n\n"))(require("../tools/domprops.json"), exports); 7 | -------------------------------------------------------------------------------- /test/release/acorn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | alias uglify-js=$PWD/bin/uglifyjs 4 | UGLIFY_OPTIONS=$@ 5 | 6 | minify_in_situ() { 7 | ARGS="$UGLIFY_OPTIONS --validate --in-situ" 8 | DIRS="$1" 9 | echo '> uglify-js' $DIRS $UGLIFY_OPTIONS 10 | for i in `find $DIRS -type f -name '*.js'` 11 | do 12 | ARGS="$ARGS $i" 13 | done 14 | uglify-js $ARGS 15 | } 16 | 17 | npm_install() { 18 | PKG="$1" 19 | while !(npm install $PKG); do 20 | while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done 21 | done 22 | } 23 | 24 | rm -rf tmp/acorn \ 25 | && git clone https://github.com/acornjs/acorn.git tmp/acorn \ 26 | && cd tmp/acorn \ 27 | && rm -rf .git/hooks \ 28 | && git checkout 74b59384320ced82e09da2e8fdbed16810f7379a \ 29 | && patch -l -p1 < uglify-js' $DIRS $UGLIFY_OPTIONS 10 | for i in `find $DIRS -type f -name '*.js'` 11 | do 12 | ARGS="$ARGS $i" 13 | done 14 | uglify-js $ARGS 15 | } 16 | 17 | npm_install() { 18 | PKG="$1" 19 | while !(npm install $PKG); do 20 | while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done 21 | done 22 | } 23 | 24 | rm -rf tmp/buble \ 25 | && git clone https://github.com/bublejs/buble.git tmp/buble \ 26 | && cd tmp/buble \ 27 | && rm -rf .git/hooks \ 28 | && git checkout dcc5ab02c9af6ddaad94e587c4911677340ec100 \ 29 | && patch -l -p1 < uglify-js' $DIRS $UGLIFY_OPTIONS 10 | for i in `find $DIRS -type f -name '*.js'` 11 | do 12 | ARGS="$ARGS $i" 13 | done 14 | uglify-js $ARGS 15 | } 16 | 17 | npm_install() { 18 | PKG="$1" 19 | while !(npm install $PKG); do 20 | while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done 21 | done 22 | } 23 | 24 | rm -rf tmp/butternut \ 25 | && git clone https://github.com/Rich-Harris/butternut.git tmp/butternut \ 26 | && cd tmp/butternut \ 27 | && rm -rf .git/hooks \ 28 | && patch -l -p1 < /dev/null; then NATIVE=1; fi 23 | timeout() { 24 | T=$1 25 | shift 26 | shift 27 | shift 28 | expect < uglify-js' $DIRS $UGLIFY_OPTIONS 10 | for i in `find $DIRS -type f -name '*.js'` 11 | do 12 | ARGS="$ARGS $i" 13 | done 14 | uglify-js $ARGS 15 | } 16 | 17 | npm_install() { 18 | PKG="$1" 19 | while !(npm install $PKG); do 20 | while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done 21 | done 22 | } 23 | 24 | rm -rf tmp/rollup \ 25 | && git clone https://github.com/rollup/rollup.git tmp/rollup \ 26 | && cd tmp/rollup \ 27 | && rm -rf .git/hooks \ 28 | && git checkout 3d80c06f895eab41e648ee99786fa68c72458b80 \ 29 | && patch -l -p1 < esbuild' $DIRS 10 | for i in `find $DIRS -type f -name '*.ts' | grep -v '\.d\.ts'` 11 | do 12 | echo "$i" 13 | CODE=`cat "$i"` 14 | node_modules/.bin/esbuild --loader=ts --target=esnext > "$i" < uglify-js' $DIRS $UGLIFY_OPTIONS 20 | for i in `find $DIRS -type f -name '*.js'` 21 | do 22 | ARGS="$ARGS $i" 23 | done 24 | uglify-js $ARGS 25 | } 26 | 27 | npm_install() { 28 | PKG="$1" 29 | while !(npm install $PKG); do 30 | while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done 31 | done 32 | } 33 | 34 | rm -rf tmp/rollup \ 35 | && git clone --depth 1 --branch v2.39.1 https://github.com/rollup/rollup.git tmp/rollup \ 36 | && cd tmp/rollup \ 37 | && rm -rf .git/hooks \ 38 | && patch -l -p1 < " + args.join(" ") + "\u001B[39m"); 9 | child_process.spawn(process.argv[0], args, { 10 | stdio: [ "ignore", 1, 2 ] 11 | }).on("exit", function(code) { 12 | if (code) process.exit(code); 13 | next(); 14 | }); 15 | })(); 16 | }; 17 | -------------------------------------------------------------------------------- /test/release/web-tooling-benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | alias uglify-js="node --max-old-space-size=8192 $PWD/bin/uglifyjs" 4 | UGLIFY_OPTIONS=$@ 5 | 6 | minify_in_situ() { 7 | ARGS="$UGLIFY_OPTIONS --validate --in-situ" 8 | DIRS="$1" 9 | echo '> uglify-js' $DIRS $UGLIFY_OPTIONS 10 | for i in `find $DIRS -type f -name '*.js'` 11 | do 12 | ARGS="$ARGS $i" 13 | done 14 | uglify-js $ARGS 15 | } 16 | 17 | npm_install() { 18 | PKG="$1" 19 | while !(npm install $PKG); do 20 | while !(npm cache clean --force); do echo "'npm cache clean' failed - retrying..."; done 21 | done 22 | } 23 | 24 | rm -rf tmp/web-tooling-benchmark \ 25 | && git clone --depth 1 --branch v0.5.3 https://github.com/v8/web-tooling-benchmark.git tmp/web-tooling-benchmark \ 26 | && cd tmp/web-tooling-benchmark \ 27 | && rm -rf .git/hooks \ 28 | && patch -l -p1 < { 51 | + global.process.exitCode = 42; 52 | EOF 53 | ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi 54 | minify_in_situ "src" \ 55 | && minify_in_situ "third_party" \ 56 | && rm -rf node_modules \ 57 | && npm_install --package-lock \ 58 | && rm -rf build/* \ 59 | && npm run build:terser-bundled \ 60 | && npm run build:uglify-js-bundled \ 61 | && minify_in_situ "build" \ 62 | && rm -rf dist \ 63 | && npm run build \ 64 | && minify_in_situ "dist" \ 65 | && node dist/cli.js 66 | -------------------------------------------------------------------------------- /test/ufuzz/actions.js: -------------------------------------------------------------------------------- 1 | var get = require("https").get; 2 | var parse = require("url").parse; 3 | 4 | var base, token, run_number; 5 | var expires = Date.now() + (6 * 60 - 10) * 60 * 1000; 6 | exports.init = function(url, auth, num) { 7 | base = url; 8 | token = auth; 9 | run_number = num; 10 | }; 11 | exports.should_stop = function(callback) { 12 | if (Date.now() > expires) return callback(); 13 | read(base + "/actions/runs?per_page=100", function(reply) { 14 | var runs = verify(reply, "workflow_runs").filter(function(workflow) { 15 | return workflow.status != "completed"; 16 | }).sort(function(a, b) { 17 | return b.run_number - a.run_number; 18 | }); 19 | var found = false, remaining = 20; 20 | (function next() { 21 | var workflow; 22 | do { 23 | workflow = runs.pop(); 24 | if (!workflow) return; 25 | if (!is_cron(workflow)) break; 26 | if (workflow.run_number == run_number) found = true; 27 | } while (!found); 28 | read(workflow.jobs_url, function(reply) { 29 | verify(reply, "jobs").forEach(function(job) { 30 | if (job.status != "completed") remaining--; 31 | }); 32 | if (remaining >= 0) { 33 | next(); 34 | } else { 35 | callback(); 36 | } 37 | }); 38 | })(); 39 | }); 40 | }; 41 | 42 | function is_cron(workflow) { 43 | return /^(schedule|workflow_dispatch|workflow_run)$/.test(workflow.event); 44 | } 45 | 46 | function read(url, callback) { 47 | var done = function(reply) { 48 | done = function() {}; 49 | callback(reply); 50 | }; 51 | var options = parse(url); 52 | options.headers = { 53 | "Authorization": "Token " + token, 54 | "User-Agent": "UglifyJS", 55 | }; 56 | get(options, function(response) { 57 | var chunks = []; 58 | response.setEncoding("utf8"); 59 | response.on("data", function(chunk) { 60 | chunks.push(chunk); 61 | }).on("end", function() { 62 | var reply; 63 | try { 64 | reply = JSON.parse(chunks.join("")); 65 | } catch (e) {} 66 | done(reply); 67 | }).on("error", function() { 68 | done(); 69 | }); 70 | }).on("error", function() { 71 | done(); 72 | }); 73 | } 74 | 75 | function verify(reply, field) { 76 | if (!reply) return []; 77 | var values = reply[field]; 78 | if (!Array.isArray(values)) return []; 79 | return values.filter(function(value) { 80 | return value; 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /test/ufuzz/job.js: -------------------------------------------------------------------------------- 1 | var actions = require("./actions"); 2 | var child_process = require("child_process"); 3 | 4 | var args = [ 5 | "--max-old-space-size=2048", 6 | "test/ufuzz", 7 | ]; 8 | var iterations; 9 | switch (process.argv.length) { 10 | case 3: 11 | iterations = +process.argv[2]; 12 | args.push(iterations); 13 | break; 14 | case 5: 15 | actions.init(process.argv[2], process.argv[3], +process.argv[4]); 16 | break; 17 | default: 18 | throw new Error("invalid parameters"); 19 | } 20 | var tasks = [ run(), run() ]; 21 | if (iterations) return; 22 | var alive = setInterval(function() { 23 | actions.should_stop(function() { 24 | clearInterval(alive); 25 | tasks.forEach(function(kill) { 26 | kill(); 27 | }); 28 | }); 29 | }, 8 * 60 * 1000); 30 | 31 | function run() { 32 | var child, stdout, stderr, log; 33 | spawn(); 34 | return function() { 35 | clearInterval(log); 36 | child.removeListener("exit", respawn); 37 | child.kill(); 38 | }; 39 | 40 | function spawn() { 41 | child = child_process.spawn("node", args, { 42 | stdio: [ "ignore", "pipe", "pipe" ] 43 | }).on("exit", respawn); 44 | stdout = ""; 45 | child.stdout.on("data", function(data) { 46 | stdout += data; 47 | }); 48 | stderr = ""; 49 | child.stderr.on("data", trap).pipe(process.stdout); 50 | log = setInterval(function() { 51 | stdout = stdout.replace(/[^\r\n]+\r(?=[^\r\n]+\r)/g, ""); 52 | var end = stdout.lastIndexOf("\r"); 53 | if (end < 0) return; 54 | console.log(stdout.slice(0, end)); 55 | stdout = stdout.slice(end + 1); 56 | }, 5 * 60 * 1000); 57 | } 58 | 59 | function respawn() { 60 | console.log(stdout.replace(/[^\r\n]*\r/g, "")); 61 | clearInterval(log); 62 | if (!iterations) { 63 | spawn(); 64 | } else if (process.exitCode) { 65 | tasks.forEach(function(kill) { 66 | kill(); 67 | }); 68 | } 69 | } 70 | 71 | function trap(data) { 72 | stderr += data; 73 | if (~stderr.indexOf("!!!!!! Failed... round ")) { 74 | process.exitCode = 1; 75 | child.stderr.removeListener("data", trap); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/ufuzz/options.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "compress": false, 4 | "mangle": false, 5 | "module": false, 6 | "output": { 7 | "beautify": true, 8 | "braces": true 9 | }, 10 | "rename": true 11 | }, 12 | { 13 | "compress": false, 14 | "module": false 15 | }, 16 | { 17 | "mangle": false, 18 | "module": false 19 | }, 20 | { 21 | "module": false 22 | }, 23 | { 24 | "ie": true, 25 | "module": false, 26 | "output": { 27 | "semicolons": false 28 | }, 29 | "toplevel": true 30 | }, 31 | { 32 | "compress": { 33 | "hoist_vars": true, 34 | "keep_infinity": true, 35 | "passes": 1e6, 36 | "unsafe": true 37 | }, 38 | "keep_fargs": true, 39 | "keep_fnames": true, 40 | "module": false, 41 | "toplevel": true 42 | }, 43 | { 44 | "compress": { 45 | "passes": 1e6, 46 | "sequences": 1e6, 47 | "unsafe": true, 48 | "unsafe_Function": true, 49 | "unsafe_math": true, 50 | "unsafe_proto": true, 51 | "unsafe_regexp": true 52 | }, 53 | "module": false 54 | } 55 | ] 56 | -------------------------------------------------------------------------------- /tools/exports.js: -------------------------------------------------------------------------------- 1 | exports["Dictionary"] = Dictionary; 2 | exports["is_statement"] = is_statement; 3 | exports["List"] = List; 4 | exports["minify"] = minify; 5 | exports["parse"] = parse; 6 | exports["push_uniq"] = push_uniq; 7 | exports["TreeTransformer"] = TreeTransformer; 8 | exports["TreeWalker"] = TreeWalker; 9 | -------------------------------------------------------------------------------- /tools/tty.js: -------------------------------------------------------------------------------- 1 | // workaround for tty output truncation on Node.js 2 | try { 3 | // prevent buffer overflow and other asynchronous bugs 4 | process.stdout._handle.setBlocking(true); 5 | process.stderr._handle.setBlocking(true); 6 | } catch (e) { 7 | // ensure output buffers are flushed before process termination 8 | var exit = process.exit; 9 | if ("bufferSize" in process.stdout) process.exit = function() { 10 | var args = [].slice.call(arguments); 11 | process.once("uncaughtException", function() { 12 | (function callback() { 13 | if (process.stdout.bufferSize || process.stderr.bufferSize) { 14 | setTimeout(callback, 1); 15 | } else { 16 | exit.apply(process, args); 17 | } 18 | })(); 19 | }); 20 | throw exit; 21 | }; 22 | } 23 | --------------------------------------------------------------------------------