Compare commits

..

126 Commits

Author SHA1 Message Date
Alex Lam S.L
a84564d1a8 v2.8.19 2017-03-31 12:26:10 +08:00
Alex Lam S.L
c595b84032 fix catch symbol mangling (#1734)
Only need to look up the immediate non-block/catch scope for the same-name special case.

fixes #1733
2017-03-31 02:57:47 +08:00
Alex Lam S.L
7cb1adf455 remove paranthesis for -(x*y) (#1732) 2017-03-30 16:09:00 +08:00
Alex Lam S.L
7bea38a05d optimize try-catch-finally (#1731)
- eliminate empty blocks
- flatten out if try-block does not throw
2017-03-30 12:16:58 +08:00
Alex Lam S.L
0f910ee25c improve tests from #1726 (#1729) 2017-03-30 00:13:46 +08:00
Alex Lam S.L
beb9659778 speed up IIFE elimination (#1728)
- `side_effects` will clean up inner statements, so checking for an empty function body should suffice
- drop side effects when dropping `return` from statement
2017-03-29 23:27:35 +08:00
Alex Lam S.L
f1a833a7aa speed up equivalent_to() and AST_Switch (#1727) 2017-03-29 22:08:26 +08:00
Alex Lam S.L
2e41cd6394 fix missing parentheses around NaN/Infinity shorthands (#1726)
fixes #1724
fixes #1725
2017-03-29 20:53:03 +08:00
Alex Lam S.L
09f77c7d4d output optimal representations of NaN & Infinity (#1723)
- move these optimisations out from `Compressor` to `OutputStream`
- fixes behaviour inconsistency when running uglified code from global or module levels due to redefinition
2017-03-29 18:31:55 +08:00
Alex Lam S.L
fef0bf9ee0 improve beautified output of switch blocks (#1721) 2017-03-29 04:40:05 +08:00
Alex Lam S.L
ae740b933f v2.8.18 2017-03-29 03:13:30 +08:00
Alex Lam S.L
ec7f37f314 remove UGLIFY_DEBUG (#1720)
fixes #1719
2017-03-29 01:27:24 +08:00
Alex Lam S.L
eb48a035e7 fix corner case in unused (#1718)
When fixing catch-related issue in #1715, it tries to optimise for duplicate definitions but did not take anonymous functions into account.

Remove such optimisation for now and we can cover this as a more general rule later.
2017-03-29 01:00:21 +08:00
Alex Lam S.L
6ab3224c0d v2.8.17 2017-03-28 21:49:04 +08:00
Alex Lam S.L
c909ffb715 fix unused on var of the same name within catch (#1716)
fixes #1715
2017-03-28 21:25:49 +08:00
Alex Lam S.L
f71f4905b0 fix is_number() on += (#1714)
fixes #1710
2017-03-28 17:08:16 +08:00
Alex Lam S.L
fb177a6312 drop anonymous function name when overshadowed by other declarations (#1712)
fixes #1709
2017-03-28 17:02:20 +08:00
Alex Lam S.L
65da9acce6 handle var within catch of the same name (#1711)
The following code prints `1`:

var a = 1;
!function(){
  a = 4;
  try{
    throw 2;
  } catch (a) {
    var a = 3;
  }
}();
console.log(a);

fixes #1708
2017-03-28 16:42:39 +08:00
Alex Lam S.L
67d0237f73 fix tail trimming of switch blocks (#1707)
now guarded under `dead_code`

fixes #1705
2017-03-28 03:59:13 +08:00
Alex Lam S.L
984a21704e fix mangle for variable declared within catch block (#1706)
fixes #1704
2017-03-28 03:26:35 +08:00
Alex Lam S.L
aa3f647656 ufuzz: workaround for Function.toString() v2 (#1700) 2017-03-27 21:49:08 +08:00
Alex Lam S.L
c526da59a1 has_side_effects() should take AST_Switch.expression into account (#1699)
fixes #1698
2017-03-27 18:09:35 +08:00
Alex Lam S.L
581630e0a7 fix typeof side effects (#1696)
`statement_to_expression()` drops `typeof` even if it operates on undeclared variables.

Since we now have `drop_side_effect_free()`, replace and remove this deprecated functionality.
2017-03-27 04:37:42 +08:00
Alex Lam S.L
f5952933a0 preserve side effects in switch expression (#1694)
fixes #1690
2017-03-27 02:32:46 +08:00
Alex Lam S.L
f001e4cb9d fix cascade on anonymous function reference (#1693)
Unlike normal variables and even function definitions, these cannot be reassigned, even though assignment expressions would "leak" the assigned value as normal.
2017-03-27 01:58:21 +08:00
Alex Lam S.L
57ce5bd9e0 handle overlapped variable definitions (#1691)
Process variable definitions with or without assigned values against:
- `arguments`
- named function arguments
- multiple definitions within same scope

Essentially demote variable declarations with no value assignments.

Also fixed invalid use of `AST_VarDef` over `arguments` - should use a member of `AST_SymbolDeclaration` instead.
2017-03-27 01:30:21 +08:00
Alex Lam S.L
861a79ac9f fix delete related issues in collapse_vars and reduce_vars (#1689) 2017-03-26 19:14:30 +08:00
Alex Lam S.L
00996afd2c ufuzz: workaround function name and toString() (#1688)
fixes #1686
2017-03-26 18:18:44 +08:00
Alex Lam S.L
e76fb354eb fix cascade on delete operator (#1687)
Conditions including strict mode would make `delete` return `true` or `false`, and are too complex to be evaluated by the compressor.

Suppress assignment folding into said operator.

fixes #1685
2017-03-26 18:08:44 +08:00
Alex Lam S.L
3276740779 fallthrough should not execute case expression (#1683)
- de-duplicate trailing cases only, avoid all potential side-effects
- enable switch statement fuzzing

fixes #1680
2017-03-26 16:52:38 +08:00
kzc
5509e51098 optimize conditional when condition symbol matches consequent (#1684) 2017-03-26 16:36:33 +08:00
Alex Lam S.L
94f84727ce suppress switch branch de-duplication upon side effects (#1682)
fixes #1679
2017-03-26 13:32:43 +08:00
Alex Lam S.L
8a4f86528f fix side-effects detection on switch statements (#1678)
extension of #1675
2017-03-26 12:05:44 +08:00
Peter van der Zee
adb0e882e9 Improve fuzzer. :) (#1665)
@qfox	Put value constants in a global constant			74c0fb9
 @qfox	And the other string based values as well			a5033c5
 @qfox	Be more strict about parameters, allow max to be optional			9c7ce70
 @qfox	Support a `V` (capital) flag to only log out at intervals			2d822c7
 @qfox	Fewer magic variables			a6a9a7c
 @qfox	Fix decrement such that a function is created when n=1			7e4b017
 @qfox	Add more values			64e596e
 @qfox	Make `b` appear more often			d33191a
 @qfox	Add functions that contain (only..) functions			29a86e3
 @qfox	Allow the block statement to contain multiple statements			7570484
 @qfox	Make the interval count a constant			d587ad8
 @qfox	Enable mangling, disable post-processing  …			4dc8d35
 @qfox	Add more simple value that may trigger syntactic errors			8496d58
 @qfox	Add `else` to some `if` statements			a4aed65
 @qfox	Move iife to expr generator, fix missing recursion arg			e453159
 @qfox	Improve output on error where it wasnt printing the last code properly			4565a1a
 @qfox	Add switch statement to generator			ceafa76
 @qfox	Add var statement, support optional comma for expr generator			b83921b
 @qfox	Expression generator should use a simple value instead of `0` as recu…  …			9d1a5c7
 @qfox	const -> var to keep things es5...			0143099
 @qfox	Add more simple values that may trigger edge cases			5e124f1
 @qfox	Add central name generator, take special care for global functions			aeb7682
 @qfox	Add some `return` and function declaration cases to statement generator			6c9c3cc
 @qfox	Exclude switches from generator for now			91124b2

Put value constants in a global constant

And the other string based values as well

Be more strict about parameters, allow max to be optional

Support a `V` (capital) flag to only log out at intervals

Fewer magic variables

Fix decrement such that a function is created when n=1

Add more values

Make `b` appear more often

Add functions that contain (only..) functions

Allow the block statement to contain multiple statements

Make the interval count a constant

Enable mangling, disable post-processing

Mangling is kind of the whole point...

Similarly, to beautify the minified code afterwards may supress bugs so it's probably best not to beautify the code prematurely. And there's no point anyways since you won't see it most of the time and only care about the main input anyways.

Add more simple value that may trigger syntactic errors

Add `else` to some `if` statements

Move iife to expr generator, fix missing recursion arg

Improve output on error where it wasnt printing the last code properly

Add switch statement to generator

Add var statement, support optional comma for expr generator

Expression generator should use a simple value instead of `0` as recursion default

const -> var to keep things es5...

Add more simple values that may trigger edge cases

Add central name generator, take special care for global functions

Add some `return` and function declaration cases to statement generator

Exclude switches from generator for now

Enable switch generation because #1667 was merged

Add typeof generator

Add some elision tests

Add a new edge case that returns an object explicitly

Add all binary ops to try and cover more paths

Forgot four binops and added `Math` to var name pool

Harden the incremental pre/postfix tests

Improve switch generator, allow `default` to appear at any clause index

Add try/catch/finally generation

Prevent function statements being generated

Add edge case with decremental op and a group

Disable switch generation until #1679 and #1680 are solved

Only allow `default` clause as last clause for now

Tentatively enable `throw`, `break` and `continue` statements when in valid contexts
2017-03-26 12:04:50 +08:00
Alex Lam S.L
f83d370f57 improve switch optimisations (#1677)
- correctly determine reachability of (default) branches
- gracefully handle multiple default branches
- optimise branches with duplicate bodies

fixes #376
fixes #441
fixes #1674
2017-03-26 05:15:46 +08:00
Alex Lam S.L
b19aa58cff fix has_side_effects() (#1675)
`AST_Try` is an `AST_Block`, so besides try block we also need to inspect catch and finally blocks for possible side effects.

Also extend this functionality to handle `AST_If` and `AST_LabeledStatement` while we are at it.

fixes #1673
2017-03-25 23:03:26 +08:00
Alex Lam S.L
0a65de89b9 fix reduce_vars on AST_Switch (#1671)
Take conditional nature of switch branches into account.

fixes #1670
2017-03-25 21:17:30 +08:00
Alex Lam S.L
6e86ee950d fix typeof side-effects (#1669)
`has_side_effects()` does not take `typeof`'s magical power of not tripping over undeclared variable into account.

fixes #1668
2017-03-25 17:40:18 +08:00
Alex Lam S.L
8ca2401ebe fix dead_code on AST_Switch (#1667)
Need to call `extract_declarations_from_unreachable_code()`.

fixes #1663
2017-03-25 16:21:42 +08:00
Alex Lam S.L
491f16c766 v2.8.16 2017-03-25 03:21:16 +08:00
Alex Lam S.L
a30092e20f fix invalid AST_For.init (#1657)
Turns out the only place in `Compressor` which can generate invalid `AST_For.init` is within `drop_unused()`, so focus the fix-up efforts.

supercedes #1652
fixes #1656
2017-03-25 03:18:36 +08:00
Alex Lam S.L
b1abe92e1a introduce ufuzz.js (#1655)
closes #1647
2017-03-25 01:46:12 +08:00
Alex Lam S.L
b454ce667e Update ISSUE_TEMPLATE.md 2017-03-24 23:12:58 +08:00
Alex Lam S.L
32283a0def fix cascade of evaluate optimisation (#1654)
Operator has changed, so break out from rest of the rules.

fixes #1649
2017-03-24 22:09:19 +08:00
Alex Lam S.L
ac51d4c5a0 fix corner case in AST_For.init (#1652)
Enforce `null` as value for empty initialisation blocks.

fixes #1648
2017-03-24 19:31:17 +08:00
Alex Lam S.L
0432a7abb9 fix assignment extraction from conditional (#1651)
fixes #1645
fixes #1646
2017-03-24 18:52:48 +08:00
Alex Lam S.L
f3a1694a41 fix assignment substitution in sequences (#1643)
take side effects of binary boolean operations into account

fixes #1639
2017-03-24 14:30:31 +08:00
Alex Lam S.L
2e0dc97003 improve error marker placement (#1644)
For AST_UnaryPrefix, points to the operator rather than end of expression.
2017-03-24 14:28:40 +08:00
Alex Lam S.L
701035621d fix expect_stdout (#1642)
`compress()` may modify input ASTs

add tests for #1627 & #1640
2017-03-24 13:19:50 +08:00
kzc
79334dda10 fix regression: CLI options with hyphens like -b ascii-only (#1640)
fixes #1637
2017-03-24 11:55:03 +08:00
Alex Lam S.L
e918748d88 improve collapsible value detection (#1638)
- #1634 bars variables with cross-scope references in between to collapse
- but if assigned value is side-effect-free, no states can be modified, so it is safe to move
2017-03-24 02:55:32 +08:00
Alex Lam S.L
6b2f34769a v2.8.15 2017-03-23 13:36:47 +08:00
Alex Lam S.L
48ffbef51d account for cross-scope modifications in collapse_vars (#1634)
mostly done by @kzc

fixes #1631
2017-03-23 07:17:34 +08:00
Alex Lam S.L
c0f3feae9f introduce compressor.info() (#1633)
report the following only when `options.warnings = "verbose"`
- unused elements due to inlining
- collpased variables
2017-03-23 06:49:49 +08:00
Alex Lam S.L
a00040dd93 fix a bug in simple_glob (#1632)
- "?" should not match "/"
- other minor clean-ups
2017-03-23 06:11:16 +08:00
Alex Lam S.L
ee95c1b38b metadata cleanup (#1630)
- mention performance anomaly in Node 7 and drop from CI
- remove unused npm "scripts"
- mark browserify dependency as optional
- stop `test/mozilla-ast.js` from spamming console output in later versions of Node.js
2017-03-23 01:31:46 +08:00
Alex Lam S.L
4bceb85cbf throw parse error on invalid assignments (#1627)
fixes #1626
2017-03-21 14:11:32 +08:00
Alex Lam S.L
30a75049f5 v2.8.14 2017-03-19 15:24:57 +08:00
Alex Lam S.L
a3cc3a9b87 make expect_stdout work on Node.js 0.12 (#1623)
That particular version of Node.js has messed up error messages, so provide a version-specific workaround.

Also fixed an formatting issue which would cause `expect_stdout` to fail if error message contains excerpts of input.

Apply `expect_stdout` to more applicable tests.
2017-03-19 12:00:32 +08:00
Alex Lam S.L
96f8befdd7 fix commit 88fb83a (#1622)
The following is wrong:
    `a == (b ? a : c)` => `b`
Because:
- `b` may not be boolean
- `a` might have side effects
- `a == a` is not always `true` (think `NaN`)
- `a == c` is not always `false`
2017-03-19 11:59:42 +08:00
Alex Lam S.L
cd58635dcc fix AST_Binary.lift_sequences() (#1621)
Commit eab99a1c fails to account for side effects from compound assignments.
2017-03-19 03:04:22 +08:00
Alex Lam S.L
274331d0ea transform String.charAt() to index access (#1620)
Guarded by `unsafe` as `charAt()` can be overridden.
2017-03-19 02:17:15 +08:00
Alex Lam S.L
0489d6de64 handle runtime errors in expect_stdout (#1618)
allow test to pass if both `input` and `expect` throws the same kind of error
2017-03-18 02:33:51 +08:00
Alex Lam S.L
fb092839c2 fix top-level directives in compress tests (#1615)
`input` and `expect` are parsed as `AST_BlockStatement` which does not support `AST_Directive` by default.

Emulate that by transforming preceding `AST_SimpleStatement`s of `AST_String` into `AST_Directive`.
2017-03-18 01:56:15 +08:00
Christian Maughan Tegnér
b7c112eefe Add --in-source-map inline documentation (#1611) 2017-03-17 03:08:38 +08:00
Alex Lam S.L
b2b8a0d386 v2.8.13 2017-03-17 02:01:33 +08:00
Alex Lam S.L
ac40301813 fix chained evaluation (#1610)
`reduce_vars` enables substitution of variables but did not clone the value's `AST_Node`.

This confuses `collapse_vars` and result in invalid AST and subsequent crash.

fixes #1609
2017-03-17 00:26:48 +08:00
Alex Lam S.L
3563d8c09e extend test/run-tests.js to optionally execute uglified output (#1604)
fixes #1588
2017-03-16 23:20:06 +08:00
Alex Lam S.L
5ae04b3545 make collapse_vars consistent with toplevel (#1608)
fixes #1605
2017-03-16 13:22:26 +08:00
Alex Lam S.L
a80b228d8b fix hoist_vars on reduce_vars (#1607)
`hoist_vars` converts variable declarations into plain assignments, which then confuses `reduce_vars`

fixes #1606
2017-03-16 12:03:30 +08:00
Alex Lam S.L
cf4bf4ceb1 fix stack issues with AST_Node.evaluate() (#1603)
As patched in #1597, `make_node_from_constant()` makes inconsistent and sometimes incorrect calls to `optimize()` and `transform()`.

Fix those issues properly by changing the semantics of `evaluate()` and `make_node_from_constant()`, with the side effect that `evaluate()` no longer eagerly converts constant to `AST_Node`.
2017-03-16 01:02:59 +08:00
Alex Lam S.L
8223b2e0db fix AST_Node.optimize() (#1602)
Liberal use of `Compressor.transform()` and `AST_Node.optimize()` presents an issue for look-up operations like `TreeWalker.in_boolean_context()` and `TreeWalker.parent()`.

This is an incremental fix such that `AST_Node.optimize()` would now contain the correct stack information when called correctly.
2017-03-15 18:44:13 +08:00
Alex Lam S.L
381bd3836e minor clean-ups (#1600)
- remove obsolete optimisation in `AST_Binary` after #1477
- improve `TreeWalker.has_directive()` readability and resilience against multiple visits
2017-03-14 13:19:05 +08:00
Alex Lam S.L
919d5e3482 v2.8.12 2017-03-11 05:00:55 +08:00
Alex Lam S.L
e3a3db73ae temporary fix for boolean bug (#1597)
fixes #1592
2017-03-11 04:59:55 +08:00
Alex Lam S.L
d9344f30b8 disallow parameter substitution for named IIFEs (#1596)
Self-referenced function has non-fixed values assigned to its parameters.

Let `unused` & `!keep_fnames` do the scanning, then apply `reduce_vars` only to unnamed functions.

fixes #1595
2017-03-11 03:34:55 +08:00
Alex Lam S.L
be80f7e706 support multi-line string in tests (#1590)
`expect_exact` sometimes have multiple lines and `\n` are hard to read.

Use array of strings to emulate line breaks and improve readability.
2017-03-10 11:27:30 +08:00
Alex Lam S.L
cf45e2f79b fixup for #1585 (#1589)
As patched on `harmony`, `statement()` is the only user of `embed_tokens()` with a missing error branch.

Updated test case and match up with `harmony` to facilitate future merging.
2017-03-10 10:49:41 +08:00
Alex Lam S.L
8354758f30 v2.8.11 2017-03-10 04:17:21 +08:00
Alex Lam S.L
9e6b128374 fix catch variable reference in IE8 (#1587)
`AST_Scope.def_variable()` will overwrite `AST_Symbol.thedef`, so save a copy before calling.

fixes #1586
2017-03-10 03:15:21 +08:00
Michael Mior
93cdb194f4 Correctly raise a parse exception with a missing loop body (#1585) 2017-03-10 03:08:43 +08:00
Alex Lam S.L
b633706ce4 fix & improve function argument compression (#1584)
- one-use function call => IIFE should take `eval()` & `arguments` into account
- if unused parameter cannot be eliminated, replace it with `0`

fixes #1583
2017-03-09 19:11:05 +08:00
Alex Lam S.L
e9920f7ca1 v2.8.10 2017-03-09 05:48:06 +08:00
Alex Lam S.L
7e465d4a01 scan RHS of dropped assignments (#1581)
- similar case as #1578 but against #1450 instead
- fix `this` binding in #1450 as well

closes #1580
2017-03-09 05:22:27 +08:00
Alex Lam S.L
aa80ee349d remove checkboxes from Issues template 2017-03-08 19:19:54 +08:00
Alex Lam S.L
80e81765cf explain how to make a proper bug report (#1579)
fixes #1574
2017-03-08 18:56:01 +08:00
Alex Lam S.L
711f88dcb4 scan assignment value in drop_unused() (#1578)
those were not optimised for `unused` before, which made it necessary for `reduce_vars` to have separate steps for `keep_fnames`

docs update by @kzc

closes #1577
2017-03-08 18:37:32 +08:00
Alex Lam S.L
344d11d591 v2.8.9 2017-03-08 12:41:22 +08:00
Alex Lam S.L
c7cdcf06a6 fix function name eliminiation (#1576)
Function expression can be assigned to a variable and be given a name. Ensure function name is the reduced variable before clearing it out.

fixes #1573
fixes #1575
2017-03-08 12:39:57 +08:00
Alex Lam S.L
3ee55748d4 only run benchmark & jetstream on CI (#1571) 2017-03-08 06:00:51 +08:00
Alex Lam S.L
dedbeeff15 plan B for IE8 do-while semi-colon fix (#1572)
- omitting trailing semi-colon in do-while breaks non-browser parser, e.g. uglify-js 1.x
- trailing semi-colon only breaks IE8 if followed by `else` or `while`
- always use braces in do-while body to workaround 2nd case with no size loss in compression

fixes #1568
2017-03-08 05:07:05 +08:00
Alex Lam S.L
bd6dee52ab fix return from recursive IIFE (#1570)
`side-effects` did not account for IIFEs being able to reference itself thus making its return value potentially significant
2017-03-08 03:31:51 +08:00
Alex Lam S.L
144052ca49 v2.8.8 2017-03-07 19:58:41 +08:00
Alex Lam S.L
65c848cc6f include benchmark.js in test suite (#1564)
- report file sizes and overall run time
- exit with non-zero code upon error
2017-03-07 19:25:12 +08:00
Alex Lam S.L
8a8a94a596 fix deep cloning of labels (#1565)
`AST_Label.references` get `.initialize()` to `[]` every time after `.clone()`

So walk down the tree to pick up the cloned `AST_LoopControl` pieces and put it back together.
2017-03-07 18:38:27 +08:00
Alex Lam S.L
8153b7bd8a transform function calls to IIFEs (#1560)
- expose function body to call sites for potential optimisations
- suppress substitution of variable used within `AST_Defun`
2017-03-07 15:37:52 +08:00
Alex Lam S.L
d787d70127 avoid substitution of global variables (#1557)
- unless `toplevel` is enabled
- global `const` works as before
2017-03-07 03:11:03 +08:00
kzc
3ac2421932 collapse_vars: do not replace a constant in loop condition or init (#1562) 2017-03-07 01:42:33 +08:00
Alex Lam S.L
a9fc9ddc33 suppress semicolons after do/while (#1556)
- unless both `beautify` & `screw-ie8` are enabled
- deprecate workaround for if-do-while-else

fixes #186
2017-03-06 17:31:35 +08:00
Alex Lam S.L
a5d62a3fc6 v2.8.7 2017-03-05 17:17:08 +08:00
Alex Lam S.L
067e5a5762 fixup for #1553 (#1555)
- `++a` is the one that is foldable
- transform `a++` into `++a` for better optimisation
2017-03-05 17:15:37 +08:00
Alex Lam S.L
33b5f31984 v2.8.6 2017-03-05 15:48:28 +08:00
Alex Lam S.L
35a849dc48 collapse assignment with adjacent subsequent usage (#1553)
- consolidate `cascade` optimisations
- support ++/-- postfixes
- remove redundant optimisation identified in #1460

fixes #368
2017-03-05 14:56:14 +08:00
Alex Lam S.L
b70591be1a handle variable declaration within catch blocks (#1546)
accounts for IE8- scoping
2017-03-05 13:13:44 +08:00
Alex Lam S.L
b33e7f88e6 improve unsafe on undefined (#1548)
`unsafe` turns undefined keyword into a variable of the same name if found, but that interferes with other related optimisations.

Keep track of such transformations to ensure zero information loss in the process.
2017-03-05 13:09:27 +08:00
Alex Lam S.L
1f0333e9f1 stay safe with constants in IE8- (#1547)
- `undefined` etc. can be redefined at top-level for IE8-, so disable related optimisations
- fixed `--support-ie8` catch mangle bug
2017-03-05 12:51:11 +08:00
Alex Lam S.L
eb98a7f2f3 fix handling of shebang and preamble (#1545)
fixes #1332
2017-03-05 12:16:02 +08:00
Alex Lam S.L
78d1bb92d4 fix a corner case in #1530 (#1552) 2017-03-05 12:12:59 +08:00
Alex Lam S.L
ea9ab9fb0e resolve issue with outdated version of async (#1549)
fixes #746
2017-03-05 01:54:20 +08:00
kzc
ce54c9ccee disallow collapse_vars constant replacement in for-in statements (#1543) 2017-03-04 02:39:54 +08:00
Alex Lam S.L
07accd2fbb process code with implicit return statement (#1522)
Bookmarklet for instance implicitedly assumes a "completion value" without using `return`.
The `expression` option now supports such use cases.
Optimisations on IIFEs also enhanced.

fixes #354
fixes #543
fixes #625
fixes #628
fixes #640
closes #1293
2017-03-03 18:13:07 +08:00
Alex Lam S.L
18059cc94f compress numerical expressions (#1513)
safe operations
- `a === b` => `a == b`
- `a + -b`  => `a - b`
- `-a + b`  => `b - a`
- `a+ +b`   => `+b+a`

associative operations
(bit-wise operations are safe, otherwise `unsafe_math`)
- `a + (b + c)`       => `(a + b) + c`
- `(n + 2) + 3`       => `5 + n`
- `(2 * n) * 3`       => `6 * n`
- `(a | 1) | (2 | d)` => `(3 | a) | b`

fixes #412
2017-03-03 18:04:32 +08:00
Alex Lam S.L
b5e0e8c203 facilitate fix for #1531 (#1542) 2017-03-03 07:12:24 +08:00
Alex Lam S.L
e5cb9275df v2.8.5 2017-03-03 05:14:21 +08:00
Alex Lam S.L
17b81350d4 fix chained assignment with unused (#1540)
When #1450 optimises `a=b=42`, it stops after the first variable even if both are unused.

fixes #1539
2017-03-03 04:45:20 +08:00
kzc
4d63d4f5b3 collapse_vars should not replace constant in for-in init section (#1538)
fixes #1537
2017-03-03 03:51:15 +08:00
Alex Lam S.L
70d72ad806 properly cover all cases of for-in loop variables (#1536) 2017-03-03 02:39:57 +08:00
Alex Lam S.L
fe9227a41b fix reference marking in for-in loops (#1535)
fixes #1533
2017-03-03 00:56:06 +08:00
Alex Lam S.L
b49e142a26 disable do{...}while(false) optimisation (#1534)
- fails to handle `break` in body

fixes #1532
2017-03-03 00:54:41 +08:00
kzc
ee3b39b909 optimize trivial IIFEs returning constants (#1530) 2017-03-02 15:11:40 +08:00
Alex Lam S.L
9699ffb1af trim unused invocation parameters (#1526) 2017-03-02 11:33:59 +08:00
Alex Lam S.L
fdc9b9413b minor improvement to string optimisation (#1514)
- "" + "a"     => "a"
- "" + a + "b" => a + "b"
- "a" + ""     => "a" (improving on #45)
2017-03-02 11:31:39 +08:00
Alex Lam S.L
40ceddb48a v2.8.4 2017-03-02 00:24:49 +08:00
Alex Lam S.L
7aa69117e1 fix corner cases in reduce_vars (#1524)
Avoid variable substitution in the following cases:
- use of variable before declaration
- declaration within conditional code blocks
- declaration within loop body

fixes #1518
fixes #1525
2017-03-02 00:20:53 +08:00
Alex Lam S.L
bff7ad67bb v2.8.3 2017-03-01 15:28:46 +08:00
Alex Lam S.L
c2334baa48 fix crash on missing props to string_template() (#1523)
Patched up `make_node()` without `orig`.

There may be other cases where `start` could be missing, so make it print "undefined" instead of crashing.

fixes #1518
2017-03-01 15:25:26 +08:00
70 changed files with 7359 additions and 874 deletions

9
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,9 @@
- Bug report or feature request? <!-- Note: sub-optimal but correct code is not a bug -->
- `uglify-js` version (`uglifyjs -V`)
- JavaScript input - ideally as small as possible.
- The `uglifyjs` CLI command executed or `minify()` options used.
- An example of JavaScript output produced and/or the error or warning.
<!--
Note: the release version of uglify-js only supports ES5. Those wishing
to minify ES6 should use the experimental harmony branch.
-->

View File

@@ -1,10 +1,12 @@
language: node_js
before_install: "npm install -g npm"
node_js:
- "0.12"
- "0.10"
- "0.12"
- "4"
- "6"
env:
- UGLIFYJS_TEST_ALL=1
matrix:
fast_finish: true
sudo: false

View File

@@ -10,8 +10,10 @@ There's also an
[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,
Chrome and probably Safari).
Note: release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
#### Note:
- release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
ES2015+ (ES6+) code then please use the [harmony](#harmony) development branch.
- Node 7 has a known performance regression and runs `uglify-js` twice as slow.
Install
-------
@@ -68,15 +70,14 @@ The available options are:
--source-map-inline Write base64-encoded source map to the end of js output.
--in-source-map Input source map, useful if you're compressing
JS that was generated from some other original
code.
code. Specify "inline" if the source map is included
inline with the sources.
--screw-ie8 Use this flag if you don't wish to support
Internet Explorer 6/7/8.
By default UglifyJS will not try to be IE-proof.
--support-ie8 Use this flag to support Internet Explorer 6/7/8.
Equivalent to setting `screw_ie8: false` in `minify()`
for `compress`, `mangle` and `output` options.
Note: `--support-ie8` may generate incorrect code
for `try`/`catch` in ES5 compliant browsers.
--expr Parse a single expression, rather than a
program (for parsing JSON)
-p, --prefix Skip prefix for original filenames that appear
@@ -202,9 +203,10 @@ compressed JS by mapping every token in the compiled JS to its original
location.
To use this feature you need to pass `--in-source-map
/path/to/input/source.map`. Normally the input source map should also point
to the file containing the generated JS, so if that's correct you can omit
input files from the command line.
/path/to/input/source.map` or `--in-source-map inline` if the source map is
included inline with the sources. Normally the input source map should also
point to the file containing the generated JS, so if that's correct you can
omit input files from the command line.
## Mangler options
@@ -350,6 +352,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true.
- `unsafe_math` (default: false) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_proto` (default: false) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
@@ -390,11 +395,11 @@ to set `true`; it's effectively a shortcut for `foo=true`).
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
and `x = something(), x` into `x = something()`
- `collapse_vars` -- default `false`. Collapse single-use `var` and `const`
definitions when possible.
- `collapse_vars` -- Collapse single-use `var` and `const` definitions
when possible.
- `reduce_vars` -- default `false`. Improve optimization on variables assigned
with and used as constant values.
- `reduce_vars` -- Improve optimization on variables assigned with and
used as constant values.
- `warnings` -- display warnings when dropping unreachable code or unused
declarations etc.
@@ -423,6 +428,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
such as `console.info` and/or retain side effects from function arguments
after dropping the function call then use `pure_funcs` instead.
- `expression` -- default `false`. Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets.
- `keep_fargs` -- default `true`. Prevents the
compressor from discarding unused function arguments. You need this
for code which relies on `Function.length`.

View File

@@ -8,7 +8,6 @@ var sys = require("util");
var yargs = require("yargs");
var fs = require("fs");
var path = require("path");
var async = require("async");
var acorn;
var screw_ie8 = true;
var ARGS = yargs
@@ -27,7 +26,7 @@ mangling you need to use `-c` and `-m`.\
.describe("source-map-include-sources", "Pass this flag if you want to include the content of source files in the source map as sourcesContent property.")
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
.describe("screw-ie8", "Do not support Internet Explorer 6/7/8. This flag is enabled by default.")
.describe("support-ie8", "Support non-standard Internet Explorer 6/7/8 javascript. Note: may generate incorrect code for try/catch in ES5 compliant browsers.")
.describe("support-ie8", "Support non-standard Internet Explorer 6/7/8 javascript.")
.describe("expr", "Parse a single expression, rather than a program (for parsing JSON)")
.describe("p", "Skip prefix for original filenames that appear in source maps. \
For example -p 3 will drop 3 directories from file names and ensure they are relative paths. \
@@ -319,8 +318,11 @@ var STATS = {};
var TOPLEVEL = null;
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
var SOURCES_CONTENT = {};
var index = 0;
async.eachLimit(files, 1, function (file, cb) {
!function cb() {
if (index == files.length) return done();
var file = files[index++];
read_whole_file(file, function (err, code) {
if (err) {
print_error("ERROR: can't read file: " + file);
@@ -388,7 +390,9 @@ async.eachLimit(files, 1, function (file, cb) {
});
cb();
});
}, function () {
}();
function done() {
var OUTPUT_FILE = ARGS.o;
var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({
@@ -537,7 +541,7 @@ async.eachLimit(files, 1, function (file, cb) {
}));
}
}
});
}
/* -----[ functions ]----- */
@@ -557,7 +561,7 @@ function getOptions(flag, constants) {
var ast;
try {
ast = UglifyJS.parse(x, { expression: true });
ast = UglifyJS.parse(x, { cli: true, expression: true });
} catch(ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) {
print_error("Error parsing arguments for flag `" + flag + "': " + x);

View File

@@ -91,9 +91,20 @@ var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos
}, null);
var AST_Node = DEFNODE("Node", "start end", {
clone: function() {
_clone: function(deep) {
if (deep) {
var self = this.clone();
return self.transform(new TreeTransformer(function(node) {
if (node !== self) {
return node.clone(true);
}
}));
}
return new this.CTOR(this);
},
clone: function(deep) {
return this._clone(deep);
},
$documentation: "Base class of all AST nodes",
$propdoc: {
start: "[AST_Token] The first token of this node",
@@ -199,6 +210,20 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
this.label._walk(visitor);
this.body._walk(visitor);
});
},
clone: function(deep) {
var node = this._clone(deep);
if (deep) {
var refs = node.label.references;
var label = this.label;
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl
&& node.label && node.label.thedef === label) {
refs.push(node);
}
}));
}
return node;
}
}, AST_StatementWithBody);
@@ -812,9 +837,6 @@ var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
$documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
$propdoc: {
init: "[AST_Node*/S] array of initializers for this declaration."
}
}, AST_Symbol);
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
@@ -962,8 +984,8 @@ TreeWalker.prototype = {
push: function (node) {
if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive) {
this.directives[node.value] = this.directives[node.value] ? "up" : true;
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = node;
}
this.stack.push(node);
},
@@ -991,7 +1013,7 @@ TreeWalker.prototype = {
for (var i = 0; i < node.body.length; ++i) {
var st = node.body[i];
if (!(st instanceof AST_Directive)) break;
if (st.value == type) return true;
if (st.value == type) return st;
}
}
},

File diff suppressed because it is too large Load Diff

View File

@@ -46,17 +46,8 @@
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
function is_some_comments(comment) {
var text = comment.value;
var type = comment.type;
if (type == "comment2") {
// multiline comment
return /@preserve|@license|@cc_on/i.test(text);
}
return type == "comment5";
}
function is_comment5(comment) {
return comment.type == "comment5";
// multiline comment
return comment.type == "comment2" && /@preserve|@license|@cc_on/i.test(comment.value);
}
function OutputStream(options) {
@@ -86,7 +77,7 @@ function OutputStream(options) {
}, true);
// Convert comment option to RegExp if neccessary and set up comments filter
var comment_filter = options.shebang ? is_comment5 : return_false; // Default case, throw all comments away except shebangs
var comment_filter = return_false; // Default case, throw all comments away
if (options.comments) {
var comments = options.comments;
if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
@@ -98,12 +89,12 @@ function OutputStream(options) {
}
if (comments instanceof RegExp) {
comment_filter = function(comment) {
return comment.type == "comment5" || comments.test(comment.value);
return comment.type != "comment5" && comments.test(comment.value);
};
}
else if (typeof comments === "function") {
comment_filter = function(comment) {
return comment.type == "comment5" || comments(this, comment);
return comment.type != "comment5" && comments(this, comment);
};
}
else if (comments === "some") {
@@ -400,10 +391,6 @@ function OutputStream(options) {
return OUTPUT;
};
if (options.preamble) {
print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
var stack = [];
return {
get : get,
@@ -523,6 +510,17 @@ function OutputStream(options) {
}));
}
if (comments.length > 0 && output.pos() == 0) {
if (output.option("shebang") && comments[0].type == "comment5") {
output.print("#!" + comments.shift().value + "\n");
output.indent();
}
var preamble = output.option("preamble");
if (preamble) {
output.print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(output.comment_filter, self);
// Keep single line comments after nlb, after nlb
@@ -547,10 +545,6 @@ function OutputStream(options) {
output.space();
}
}
else if (output.pos() === 0 && c.type == "comment5" && output.option("shebang")) {
output.print("#!" + c.value + "\n");
output.indent();
}
});
}
});
@@ -598,6 +592,15 @@ function OutputStream(options) {
|| p instanceof AST_Call && p.expression === this;
});
PARENS([ AST_Infinity, AST_NaN ], function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this
|| p instanceof AST_Unary && p.operator != "+" && p.operator != "-"
|| p instanceof AST_Binary && p.right === this
&& (p.operator == "/" || p.operator == "%");
});
PARENS(AST_Seq, function(output){
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
@@ -783,7 +786,7 @@ function OutputStream(options) {
DEFPRINT(AST_Do, function(self, output){
output.print("do");
output.space();
self._do_print_body(output);
make_block(self.body, output);
output.space();
output.print("while");
output.space();
@@ -805,7 +808,7 @@ function OutputStream(options) {
output.print("for");
output.space();
output.with_parens(function(){
if (self.init && !(self.init instanceof AST_EmptyStatement)) {
if (self.init) {
if (self.init instanceof AST_Definitions) {
self.init.print(output);
} else {
@@ -910,10 +913,10 @@ function OutputStream(options) {
/* -----[ if ]----- */
function make_then(self, output) {
if (output.option("bracketize")) {
make_block(self.body, output);
return;
}
var b = self.body;
if (output.option("bracketize")
|| !output.option("screw_ie8") && b instanceof AST_Do)
return make_block(b, output);
// The squeezer replaces "block"-s that contain only a single
// statement with the statement itself; technically, the AST
// is correct, but this can create problems when we output an
@@ -921,18 +924,7 @@ function OutputStream(options) {
// IF *without* an ELSE block (then the outer ELSE would refer
// to the inner IF). This function checks for this case and
// adds the block brackets if needed.
if (!self.body)
return output.force_semicolon();
if (self.body instanceof AST_Do) {
// Unconditionally use the if/do-while workaround for all browsers.
// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
// croaks with "syntax error" on code like this: if (foo)
// do ... while(cond); else ... we need block brackets
// around do/while
make_block(self.body, output);
return;
}
var b = self.body;
if (!b) return output.force_semicolon();
while (true) {
if (b instanceof AST_If) {
if (!b.alternative) {
@@ -977,24 +969,24 @@ function OutputStream(options) {
self.expression.print(output);
});
output.space();
if (self.body.length > 0) output.with_block(function(){
self.body.forEach(function(stmt, i){
if (i) output.newline();
var last = self.body.length - 1;
if (last < 0) output.print("{}");
else output.with_block(function(){
self.body.forEach(function(branch, i){
output.indent(true);
stmt.print(output);
branch.print(output);
if (i < last && branch.body.length > 0)
output.newline();
});
});
else output.print("{}");
});
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
if (this.body.length > 0) {
output.newline();
this.body.forEach(function(stmt){
output.indent();
stmt.print(output);
output.newline();
this.body.forEach(function(stmt){
output.indent();
stmt.print(output);
output.newline();
});
}
});
});
DEFPRINT(AST_Default, function(self, output){
output.print("default:");
@@ -1271,10 +1263,18 @@ function OutputStream(options) {
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_Infinity, function(self, output){
output.print("Infinity");
output.print("1");
output.space();
output.print("/");
output.space();
output.print("0");
});
DEFPRINT(AST_NaN, function(self, output){
output.print("NaN");
output.print("0");
output.space();
output.print("/");
output.space();
output.print("0");
});
DEFPRINT(AST_This, function(self, output){
output.print("this");
@@ -1341,15 +1341,7 @@ function OutputStream(options) {
function force_statement(stat, output) {
if (output.option("bracketize")) {
if (!stat || stat instanceof AST_EmptyStatement)
output.print("{}");
else if (stat instanceof AST_BlockStatement)
stat.print(output);
else output.with_block(function(){
output.indent();
stat.print(output);
output.newline();
});
make_block(stat, output);
} else {
if (!stat || stat instanceof AST_EmptyStatement)
output.force_semicolon();
@@ -1398,11 +1390,11 @@ function OutputStream(options) {
};
function make_block(stmt, output) {
if (stmt instanceof AST_BlockStatement) {
if (!stmt || stmt instanceof AST_EmptyStatement)
output.print("{}");
else if (stmt instanceof AST_BlockStatement)
stmt.print(output);
return;
}
output.with_block(function(){
else output.with_block(function(){
output.indent();
stmt.print(output);
output.newline();

View File

@@ -558,6 +558,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function next_token(force_regexp) {
if (force_regexp != null)
return read_regexp(force_regexp);
if (shebang && S.pos == 0 && looking_at("#!")) {
start_token();
forward(2);
skip_line_comment("comment5");
}
for (;;) {
skip_whitespace();
start_token();
@@ -589,13 +594,6 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (PUNC_CHARS(ch)) return token("punc", next());
if (OPERATOR_CHARS(ch)) return read_operator();
if (code == 92 || is_identifier_start(code)) return read_word();
if (shebang) {
if (S.pos == 0 && looking_at("#!")) {
forward(2);
skip_line_comment("comment5");
continue;
}
}
break;
}
parse_error("Unexpected character '" + ch + "'");
@@ -697,6 +695,7 @@ function parse($TEXT, options) {
html5_comments : true,
bare_returns : false,
shebang : true,
cli : false,
});
var S = {
@@ -930,11 +929,9 @@ function parse($TEXT, options) {
expression : parenthesised(),
body : statement()
});
default:
unexpected();
}
}
unexpected();
});
function labeled_statement() {
@@ -1460,7 +1457,7 @@ function parse($TEXT, options) {
function make_unary(ctor, op, expr) {
if ((op == "++" || op == "--") && !is_assignable(expr))
croak("Invalid use of " + op + " operator");
croak("Invalid use of " + op + " operator", null, ctor === AST_UnaryPrefix ? expr.start.col - 1 : null);
return new ctor({ operator: op, expression: expr });
};
@@ -1505,9 +1502,8 @@ function parse($TEXT, options) {
};
function is_assignable(expr) {
if (!options.strict) return true;
if (expr instanceof AST_This) return false;
return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
if (options.cli) return true;
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
};
var maybe_assign = function(no_in) {

View File

@@ -75,9 +75,14 @@ SymbolDef.prototype = {
}
else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope;
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
var sym = this.orig[0];
if (!options.screw_ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope;
this.mangled_name = s.next_mangled(options, this);
var def;
if (this.defun && (def = this.defun.variables.get(this.name))) {
this.mangled_name = def.mangled_name || def.name;
} else
this.mangled_name = s.next_mangled(options, this);
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
@@ -97,18 +102,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var labels = new Dictionary();
var defun = null;
var tw = new TreeWalker(function(node, descend){
if (options.screw_ie8 && node instanceof AST_Catch) {
if (node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
scope.init_scope_vars();
scope.parent_scope = save_scope;
scope.init_scope_vars(save_scope);
descend();
scope = save_scope;
return true;
}
if (node instanceof AST_Scope) {
node.init_scope_vars();
var save_scope = node.parent_scope = scope;
node.init_scope_vars(scope);
var save_scope = scope;
var save_defun = defun;
var save_labels = labels;
defun = scope = node;
@@ -153,13 +157,19 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
(node.scope = defun.parent_scope).def_function(node);
}
else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) {
var def = defun.def_variable(node);
def.init = tw.parent().value;
|| node instanceof AST_SymbolConst) {
defun.def_variable(node);
if (defun !== scope) {
node.mark_enclosed(options);
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
node.reference(options);
}
}
}
else if (node instanceof AST_SymbolCatch) {
(options.screw_ie8 ? scope : defun)
.def_variable(node);
scope.def_variable(node).defun = defun;
}
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
@@ -209,6 +219,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
});
self.walk(tw);
// pass 3: fix up any scoping issue with IE8
if (!options.screw_ie8) {
self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) {
var name = node.name;
var refs = node.thedef.references;
var scope = node.thedef.defun;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
refs.forEach(function(ref) {
ref.thedef = def;
ref.reference(options);
});
node.thedef = def;
return true;
}
}));
}
if (options.cache) {
this.cname = options.cache.cname;
}
@@ -227,28 +255,28 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
}
});
AST_Scope.DEFMETHOD("init_scope_vars", function(){
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
this.parent_scope = null; // the parent scope
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
this.cname = -1; // the current index for mangling functions/variables
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
this.parent_scope = parent_scope; // the parent scope
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
this.cname = -1; // the current index for mangling functions/variables
});
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
var symbol = new AST_VarDef({ name: "arguments", start: this.start, end: this.end });
var def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def);
this.def_variable(new AST_SymbolVar({
name: "arguments",
start: this.start,
end: this.end
}));
});
AST_SymbolRef.DEFMETHOD("reference", function(options) {
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
var def = this.definition();
def.references.push(this);
var s = this.scope;
while (s) {
push_uniq(s.enclosed, def);
@@ -262,6 +290,11 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
}
});
AST_Symbol.DEFMETHOD("reference", function(options) {
this.definition().references.push(this);
this.mark_enclosed(options);
});
AST_Scope.DEFMETHOD("find_variable", function(name){
if (name instanceof AST_Symbol) name = name.name;
return this.variables.get(name)

View File

@@ -126,9 +126,11 @@ function merge(obj, ext) {
return count;
};
function noop() {};
function noop() {}
function return_false() { return false; }
function return_true() { return true; }
function return_this() { return this; }
function return_null() { return null; }
var MAP = (function(){
function MAP(a, f, backwards) {
@@ -185,7 +187,7 @@ function push_uniq(array, el) {
function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p){
return props[p];
return props && props[p];
});
};

View File

@@ -4,7 +4,7 @@
"homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "2.8.2",
"version": "2.8.19",
"engines": {
"node": ">=0.8.0"
},
@@ -29,9 +29,7 @@
"LICENSE"
],
"dependencies": {
"async": "~0.2.6",
"source-map": "~0.5.1",
"uglify-to-browserify": "~1.0.0",
"yargs": "~3.10.0"
},
"devDependencies": {
@@ -41,13 +39,15 @@
"estraverse": "~1.5.1",
"mocha": "~2.3.4"
},
"optionalDependencies": {
"uglify-to-browserify": "~1.0.0"
},
"browserify": {
"transform": [
"uglify-to-browserify"
]
},
"scripts": {
"shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated",
"test": "node test/run-tests.js"
},
"keywords": ["uglify", "uglify-js", "minify", "minifier"]

View File

@@ -24,26 +24,57 @@ var results = {};
var remaining = 2 * urls.length;
function done() {
if (!--remaining) {
var failures = [];
urls.forEach(function(url) {
var info = results[url];
console.log();
console.log(url);
console.log(results[url].time);
console.log("SHA1:", results[url].sha1);
console.log(info.log);
var elapsed = 0;
info.log.replace(/: ([0-9]+\.[0-9]{3})s/g, function(match, time) {
elapsed += parseFloat(time);
});
console.log("Run-time:", elapsed.toFixed(3), "s");
console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes");
console.log("SHA1 sum:", info.sha1);
if (info.code) {
failures.push(url);
}
});
if (failures.length) {
console.error("Benchmark failed:");
failures.forEach(function(url) {
console.error(url);
});
process.exit(1);
}
}
}
urls.forEach(function(url) {
results[url] = { time: "" };
results[url] = {
input: 0,
output: 0,
log: ""
};
require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
var uglifyjs = fork("bin/uglifyjs", args, { silent: true });
res.pipe(uglifyjs.stdin);
uglifyjs.stdout.pipe(createHash("sha1")).on("data", function(data) {
res.on("data", function(data) {
results[url].input += data.length;
}).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length;
}).pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex");
done();
});
uglifyjs.stderr.setEncoding("utf8");
uglifyjs.stderr.on("data", function(data) {
results[url].time += data;
}).on("end", done)
results[url].log += data;
});
uglifyjs.on("exit", function(code) {
results[url].code = code;
done();
});
});
});

View File

@@ -43,6 +43,7 @@ collapse_vars_side_effects_1: {
z = i += 4;
log(x, z, y, i);
}
f1(), f2(), f3(), f4();
}
expect: {
function f1() {
@@ -73,7 +74,9 @@ collapse_vars_side_effects_1: {
y = i += 3;
log(x, i += 4, y, i);
}
f1(), f2(), f3(), f4();
}
expect_stdout: true
}
collapse_vars_side_effects_2: {
@@ -344,9 +347,9 @@ collapse_vars_do_while: {
}
input: {
function f1(y) {
// The constant do-while condition `c` will be replaced.
// The constant do-while condition `c` will not be replaced.
var c = 9;
do { } while (c === 77);
do {} while (c === 77);
}
function f2(y) {
// The non-constant do-while condition `c` will not be replaced.
@@ -381,7 +384,8 @@ collapse_vars_do_while: {
}
expect: {
function f1(y) {
do ; while (false);
var c = 9;
do ; while (77 === c);
}
function f2(y) {
var c = 5 - y;
@@ -418,9 +422,9 @@ collapse_vars_do_while_drop_assign: {
}
input: {
function f1(y) {
// The constant do-while condition `c` will be replaced.
// The constant do-while condition `c` will be not replaced.
var c = 9;
do { } while (c === 77);
do {} while (c === 77);
}
function f2(y) {
// The non-constant do-while condition `c` will not be replaced.
@@ -455,7 +459,8 @@ collapse_vars_do_while_drop_assign: {
}
expect: {
function f1(y) {
do ; while (false);
var c = 9;
do ; while (77 === c);
}
function f2(y) {
var c = 5 - y;
@@ -821,6 +826,7 @@ collapse_vars_repeated: {
console.log(e + "!");
})("!");
}
expect_stdout: true
}
collapse_vars_closures: {
@@ -888,7 +894,8 @@ collapse_vars_unary: {
}
expect: {
function f0(o, p) {
delete o[p];
var x = o[p];
delete x;
}
function f1(n) {
return n > +!!n
@@ -1107,6 +1114,7 @@ collapse_vars_eval_and_with: {
return function() { with (o) console.log(a) };
})()();
}
expect_stdout: true
}
collapse_vars_constants: {
@@ -1141,7 +1149,7 @@ collapse_vars_constants: {
function f3(x) {
var b = x.prop;
sideeffect1();
return b + (function() { return -9; })();
return b + -9;
}
}
}
@@ -1150,7 +1158,8 @@ collapse_vars_arguments: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true,
toplevel:true
}
input: {
var outer = function() {
@@ -1165,6 +1174,7 @@ collapse_vars_arguments: {
(function(){console.log(arguments);})(7, 1);
})();
}
expect_stdout: true
}
collapse_vars_short_circuit: {
@@ -1309,9 +1319,275 @@ collapse_vars_regexp: {
};
}
(function(){
var result, rx = /ab*/g;
while (result = rx.exec('acdabcdeabbb'))
var result, s = "acdabcdeabbb", rx = /ab*/g;
while (result = rx.exec(s))
console.log(result[0]);
})();
}
expect_stdout: true
}
issue_1537: {
options = {
collapse_vars: true,
}
input: {
var k = '';
for (k in {prop: 'val'}){}
}
expect: {
var k = '';
for (k in {prop: 'val'});
}
}
issue_1562: {
options = {
collapse_vars: true,
toplevel: true,
}
input: {
var v = 1, B = 2;
for (v in objs) f(B);
var x = 3, C = 10;
while(x + 2) bar(C);
var y = 4, D = 20;
do bar(D); while(y + 2);
var z = 5, E = 30;
for (; f(z + 2) ;) bar(E);
}
expect: {
var v = 1;
for (v in objs) f(2);
var x = 3;
while(x + 2) bar(10);
var y = 4;
do bar(20); while(y + 2);
var z = 5;
for (; f(z + 2) ;) bar(30);
}
}
issue_1605_1: {
options = {
collapse_vars: true,
toplevel: false,
}
input: {
function foo(x) {
var y = x;
return y;
}
var o = new Object;
o.p = 1;
}
expect: {
function foo(x) {
return x;
}
var o = new Object;
o.p = 1;
}
}
issue_1605_2: {
options = {
collapse_vars: true,
toplevel: "vars",
}
input: {
function foo(x) {
var y = x;
return y;
}
var o = new Object;
o.p = 1;
}
expect: {
function foo(x) {
return x;
}
(new Object).p = 1;
}
}
issue_1631_1: {
options = {
cascade: true,
collapse_vars: true,
hoist_funs: true,
join_vars: true,
sequences: true,
side_effects: true,
}
input: {
var pc = 0;
function f(x) {
pc = 200;
return 100;
}
function x() {
var t = f();
pc += t;
return pc;
}
console.log(x());
}
expect: {
function f(x) {
return pc = 200, 100;
}
function x() {
var t = f();
return pc += t;
}
var pc = 0;
console.log(x());
}
expect_stdout: "300"
}
issue_1631_2: {
options = {
cascade: true,
collapse_vars: true,
hoist_funs: true,
join_vars: true,
sequences: true,
side_effects: true,
}
input: {
var a = 0, b = 1;
function f() {
a = 2;
return 4;
}
function g() {
var t = f();
b = a + t;
return b;
}
console.log(g());
}
expect: {
function f() {
return a = 2, 4;
}
function g() {
var t = f();
return b = a + t;
}
var a = 0, b = 1;
console.log(g());
}
expect_stdout: "6"
}
issue_1631_3: {
options = {
cascade: true,
collapse_vars: true,
hoist_funs: true,
join_vars: true,
sequences: true,
side_effects: true,
}
input: {
function g() {
var a = 0, b = 1;
function f() {
a = 2;
return 4;
}
var t = f();
b = a + t;
return b;
}
console.log(g());
}
expect: {
function g() {
function f() {
return a = 2, 4;
}
var a = 0, b = 1, t = f();
return b = a + t;
}
console.log(g());
}
expect_stdout: "6"
}
var_side_effects_1: {
options = {
collapse_vars: true,
}
input: {
var print = console.log.bind(console);
function foo(x) {
var twice = x * 2;
print('Foo:', twice);
}
foo(10);
}
expect: {
var print = console.log.bind(console);
function foo(x) {
print('Foo:', 2 * x);
}
foo(10);
}
expect_stdout: true
}
var_side_effects_2: {
options = {
collapse_vars: true,
}
input: {
var print = console.log.bind(console);
function foo(x) {
var twice = x.y * 2;
print('Foo:', twice);
}
foo({ y: 10 });
}
expect: {
var print = console.log.bind(console);
function foo(x) {
var twice = 2 * x.y;
print('Foo:', twice);
}
foo({ y: 10 });
}
expect_stdout: true
}
var_side_effects_3: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
var print = console.log.bind(console);
function foo(x) {
var twice = x.y * 2;
print('Foo:', twice);
}
foo({ y: 10 });
}
expect: {
var print = console.log.bind(console);
function foo(x) {
print('Foo:', 2 * x.y);
}
foo({ y: 10 });
}
expect_stdout: true
}

View File

@@ -51,6 +51,7 @@ concat_2: {
"1" + "2" + "3"
);
}
expect_stdout: true
}
concat_3: {
@@ -79,6 +80,7 @@ concat_3: {
1 + 2 + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_4: {
@@ -107,6 +109,7 @@ concat_4: {
1 + "2" + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_5: {
@@ -135,6 +138,7 @@ concat_5: {
"1" + 2 + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_6: {
@@ -163,4 +167,57 @@ concat_6: {
"1" + "2" + "3" + "4" + "5"
);
}
expect_stdout: true
}
concat_7: {
input: {
console.log(
"" + 1,
"" + "1",
"" + 1 + 2,
"" + 1 + "2",
"" + "1" + 2,
"" + "1" + "2",
"" + (x += "foo")
);
}
expect: {
console.log(
"" + 1,
"1",
"" + 1 + 2,
1 + "2",
"1" + 2,
"1" + "2",
x += "foo"
);
}
expect_stdout: true
}
concat_8: {
input: {
console.log(
1 + "",
"1" + "",
1 + 2 + "",
1 + "2" + "",
"1" + 2 + "",
"1" + "2" + "",
(x += "foo") + ""
);
}
expect: {
console.log(
1 + "",
"1",
1 + 2 + "",
1 + "2",
"1" + 2,
"1" + "2",
x += "foo"
);
}
expect_stdout: true
}

View File

@@ -797,3 +797,168 @@ no_evaluate: {
}
}
}
equality_conditionals_false: {
options = {
conditionals: false,
sequences: true,
}
input: {
function f(a, b, c) {
console.log(
a == (b ? a : a),
a == (b ? a : c),
a != (b ? a : a),
a != (b ? a : c),
a === (b ? a : a),
a === (b ? a : c),
a !== (b ? a : a),
a !== (b ? a : c)
);
}
f(0, 0, 0);
f(0, true, 0);
f(1, 2, 3);
f(1, null, 3);
f(NaN);
f(NaN, "foo");
}
expect: {
function f(a, b, c) {
console.log(
a == (b ? a : a),
a == (b ? a : c),
a != (b ? a : a),
a != (b ? a : c),
a === (b ? a : a),
a === (b ? a : c),
a !== (b ? a : a),
a !== (b ? a : c)
);
}
f(0, 0, 0),
f(0, true, 0),
f(1, 2, 3),
f(1, null, 3),
f(0/0),
f(0/0, "foo");
}
expect_stdout: true
}
equality_conditionals_true: {
options = {
conditionals: true,
sequences: true,
}
input: {
function f(a, b, c) {
console.log(
a == (b ? a : a),
a == (b ? a : c),
a != (b ? a : a),
a != (b ? a : c),
a === (b ? a : a),
a === (b ? a : c),
a !== (b ? a : a),
a !== (b ? a : c)
);
}
f(0, 0, 0);
f(0, true, 0);
f(1, 2, 3);
f(1, null, 3);
f(NaN);
f(NaN, "foo");
}
expect: {
function f(a, b, c) {
console.log(
(b, a == a),
a == (b ? a : c),
(b, a != a),
a != (b ? a : c),
(b, a === a),
a === (b ? a : c),
(b, a !== a),
a !== (b ? a : c)
);
}
f(0, 0, 0),
f(0, true, 0),
f(1, 2, 3),
f(1, null, 3),
f(0/0),
f(0/0, "foo");
}
expect_stdout: true
}
issue_1645_1: {
options = {
conditionals: true,
}
input: {
var a = 100, b = 10;
(b = a) ? a++ + (b += a) ? b += a : b += a : b ^= a;
console.log(a, b);
}
expect: {
var a = 100, b = 10;
(b = a) ? (a++ + (b += a), b += a) : b ^= a;
console.log(a,b);
}
expect_stdout: true
}
issue_1645_2: {
options = {
conditionals: true,
}
input: {
var a = 0;
function f() {
return a++;
}
f() ? a += 2 : a += 4;
console.log(a);
}
expect: {
var a = 0;
function f(){
return a++;
}
f() ? a += 2 : a += 4;
console.log(a);
}
expect_stdout: true
}
condition_symbol_matches_consequent: {
options = {
conditionals: true,
}
input: {
function foo(x, y) {
return x ? x : y;
}
function bar() {
return g ? g : h;
}
var g = 4;
var h = 5;
console.log(foo(3, null), foo(0, 7), foo(true, false), bar());
}
expect: {
function foo(x, y) {
return x || y;
}
function bar() {
return g || h;
}
var g = 4;
var h = 5;
console.log(foo(3, null), foo(0, 7), foo(true, false), bar());
}
expect_stdout: "3 7 true 4"
}

View File

@@ -162,4 +162,5 @@ regexp_literal_not_const: {
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
})();
}
expect_stdout: true
}

View File

@@ -87,6 +87,7 @@ dead_code_constant_boolean_should_warn_more: {
var x = 10, y;
var moo;
}
expect_stdout: true
}
dead_code_const_declaration: {
@@ -113,6 +114,7 @@ dead_code_const_declaration: {
var moo;
function bar() {}
}
expect_stdout: true
}
dead_code_const_annotation: {
@@ -123,6 +125,7 @@ dead_code_const_annotation: {
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused;
@@ -139,6 +142,7 @@ dead_code_const_annotation: {
var moo;
function bar() {}
}
expect_stdout: true
}
dead_code_const_annotation_regex: {
@@ -162,6 +166,7 @@ dead_code_const_annotation_regex: {
var CONST_FOO_ANN = !1;
CONST_FOO_ANN && console.log('reachable');
}
expect_stdout: true
}
dead_code_const_annotation_complex_scope: {
@@ -172,6 +177,7 @@ dead_code_const_annotation_complex_scope: {
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused_var;
@@ -206,4 +212,47 @@ dead_code_const_annotation_complex_scope: {
var meat = 'beef';
var pork = 'bad';
}
expect_stdout: true
}
try_catch_finally: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
var a = 1;
!function() {
try {
if (false) throw x;
} catch (a) {
var a = 2;
console.log("FAIL");
} finally {
a = 3;
console.log("PASS");
}
}();
try {
console.log(a);
} finally {
}
}
expect: {
var a = 1;
!function() {
var a;
a = 3;
console.log("PASS");
}();
try {
console.log(a);
} finally {
}
}
expect_stdout: [
"PASS",
"1",
]
}

View File

@@ -632,7 +632,7 @@ iife: {
}
expect: {
function f() {
~function() {}(b);
b;
}
}
}
@@ -679,3 +679,298 @@ const_assign: {
}
}
}
issue_1539: {
options = {
cascade: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f() {
var a, b;
a = b = 42;
return a;
}
}
expect: {
function f() {
return 42;
}
}
}
vardef_value: {
options = {
keep_fnames: false,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g(){
return x();
}
var a = g();
return a(42);
}
}
expect: {
function f() {
var a = function(){
return x();
}();
return a(42);
}
}
}
assign_binding: {
options = {
cascade: true,
side_effects: true,
unused: true,
}
input: {
function f() {
var a;
a = f.g, a();
}
}
expect: {
function f() {
(0, f.g)();
}
}
}
assign_chain: {
options = {
unused: true,
}
input: {
function f() {
var a, b;
x = a = y = b = 42;
}
}
expect: {
function f() {
x = y = 42;
}
}
}
issue_1583: {
options = {
keep_fargs: true,
reduce_vars: true,
unused: true,
}
input: {
function m(t) {
(function(e) {
t = e();
})(function() {
return (function(a) {
return a;
})(function(a) {});
});
}
}
expect: {
function m(t) {
(function(e) {
t = (function() {
return (function(a) {
return a;
})(function(a) {});
})();
})();
}
}
}
issue_1656: {
options = {
toplevel: true,
unused: true,
}
beautify = {
beautify: true,
}
input: {
for(var a=0;;);
}
expect_exact: "for (;;) ;"
}
issue_1709: {
options = {
unused: true,
}
input: {
console.log(
function x() {
var x = 1;
return x;
}(),
function y() {
const y = 2;
return y;
}(),
function z() {
function z() {}
return z;
}()
);
}
expect: {
console.log(
function() {
var x = 1;
return x;
}(),
function() {
const y = 2;
return y;
}(),
function() {
function z() {}
return z;
}()
);
}
expect_stdout: true
}
issue_1715_1: {
options = {
unused: true,
}
input: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a;
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a;
}
}
f();
console.log(a);
}
expect_stdout: "1"
}
issue_1715_2: {
options = {
unused: true,
}
input: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a = 2;
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
a++;
try {
x();
} catch (a) {
var a;
}
}
f();
console.log(a);
}
expect_stdout: "1"
}
issue_1715_3: {
options = {
unused: true,
}
input: {
var a = 1;
function f() {
a++;
try {
console;
} catch (a) {
var a = 2 + x();
}
}
f();
console.log(a);
}
expect: {
var a = 1;
function f() {
a++;
try {
console;
} catch (a) {
var a = x();
}
}
f();
console.log(a);
}
expect_stdout: "1"
}
issue_1715_4: {
options = {
unused: true,
}
input: {
var a = 1;
!function a() {
a++;
try {
x();
} catch (a) {
var a;
}
}();
console.log(a);
}
expect: {
var a = 1;
!function() {
a++;
try {
x();
} catch (a) {
var a;
}
}();
console.log(a);
}
expect_stdout: "1"
}

View File

@@ -52,7 +52,7 @@ and: {
a = 7;
a = false;
a = NaN;
a = 0/0;
a = 0;
a = void 0;
a = null;
@@ -67,7 +67,7 @@ and: {
a = 6 << condition && -4.5;
a = condition && false;
a = console.log("b") && NaN;
a = console.log("b") && 0/0;
a = console.log("c") && 0;
a = 2 * condition && void 0;
a = condition + 3 && null;
@@ -149,7 +149,7 @@ or: {
a = 6 << condition || -4.5;
a = condition || false;
a = console.log("b") || NaN;
a = console.log("b") || 0/0;
a = console.log("c") || 0;
a = 2 * condition || void 0;
a = condition + 3 || null;
@@ -196,10 +196,11 @@ negative_zero: {
console.log(
-0,
0,
1 / (-0),
1 / (-0)
-1/0,
-1/0
);
}
expect_stdout: true
}
positive_zero: {
@@ -216,10 +217,11 @@ positive_zero: {
console.log(
0,
-0,
1 / (0),
1 / (0)
1/0,
1/0
);
}
expect_stdout: true
}
unsafe_constant: {
@@ -243,6 +245,7 @@ unsafe_constant: {
(void 0).a
);
}
expect_stdout: true
}
unsafe_object: {
@@ -266,6 +269,7 @@ unsafe_object: {
1..b + 1
);
}
expect_stdout: true
}
unsafe_object_nested: {
@@ -289,6 +293,7 @@ unsafe_object_nested: {
2
);
}
expect_stdout: true
}
unsafe_object_complex: {
@@ -312,6 +317,7 @@ unsafe_object_complex: {
2
);
}
expect_stdout: true
}
unsafe_object_repeated: {
@@ -335,6 +341,7 @@ unsafe_object_repeated: {
1..b + 1
);
}
expect_stdout: true
}
unsafe_object_accessor: {
@@ -384,6 +391,7 @@ unsafe_function: {
({a:{b:1},b:function(){}}).a.b + 1
);
}
expect_stdout: true
}
unsafe_integer_key: {
@@ -411,6 +419,7 @@ unsafe_integer_key: {
1["1"] + 1
);
}
expect_stdout: true
}
unsafe_integer_key_complex: {
@@ -438,6 +447,7 @@ unsafe_integer_key_complex: {
2
);
}
expect_stdout: true
}
unsafe_float_key: {
@@ -465,6 +475,7 @@ unsafe_float_key: {
1["3.14"] + 1
);
}
expect_stdout: true
}
unsafe_float_key_complex: {
@@ -492,6 +503,7 @@ unsafe_float_key_complex: {
2
);
}
expect_stdout: true
}
unsafe_array: {
@@ -521,12 +533,13 @@ unsafe_array: {
[1, 2, 3, a][0] + 1,
2,
3,
NaN,
0/0,
"1,21",
5,
(void 0)[1] + 1
);
}
expect_stdout: true
}
unsafe_string: {
@@ -554,6 +567,7 @@ unsafe_string: {
"11"
);
}
expect_stdout: true
}
unsafe_array_bad_index: {
@@ -575,6 +589,7 @@ unsafe_array_bad_index: {
[1, 2, 3, 4][3.14] + 1
);
}
expect_stdout: true
}
unsafe_string_bad_index: {
@@ -596,6 +611,7 @@ unsafe_string_bad_index: {
"1234"[3.14] + 1
);
}
expect_stdout: true
}
unsafe_prototype_function: {
@@ -640,10 +656,31 @@ call_args: {
expect: {
const a = 1;
console.log(1);
+function(a) {
return 1;
}(1);
+(1, 1);
}
expect_stdout: true
}
call_args_drop_param: {
options = {
evaluate: true,
keep_fargs: false,
reduce_vars: true,
unused: true,
}
input: {
const a = 1;
console.log(a);
+function(a) {
return a;
}(a, b);
}
expect: {
const a = 1;
console.log(1);
+(b, 1);
}
expect_stdout: true
}
in_boolean_context: {
@@ -681,4 +718,87 @@ in_boolean_context: {
(foo(), !1)
);
}
expect_stdout: true
}
unsafe_charAt: {
options = {
evaluate : true,
unsafe : true
}
input: {
console.log(
"1234" + 1,
"1234".charAt(0) + 1,
"1234".charAt(6 - 5) + 1,
("12" + "34").charAt(0) + 1,
("12" + "34").charAt(6 - 5) + 1,
[1, 2, 3, 4].join("").charAt(0) + 1
);
}
expect: {
console.log(
"12341",
"11",
"21",
"11",
"21",
"11"
);
}
expect_stdout: true
}
unsafe_charAt_bad_index: {
options = {
evaluate : true,
unsafe : true
}
input: {
console.log(
"1234".charAt() + 1,
"1234".charAt("a") + 1,
"1234".charAt(3.14) + 1
);
}
expect: {
console.log(
"11",
"11",
"41"
);
}
expect_stdout: true
}
unsafe_charAt_noop: {
options = {
evaluate : true,
unsafe : true
}
input: {
console.log(
s.charAt(0),
"string".charAt(x)
);
}
expect: {
console.log(
s.charAt(0),
"string".charAt(x)
);
}
}
issue_1649: {
options = {
evaluate: true,
}
input: {
console.log(-1 + -1);
}
expect: {
console.log(-2);
}
expect_stdout: "-2";
}

View File

@@ -6,3 +6,90 @@ non_ascii_function_identifier_name: {
}
expect_exact: "function fooλ(δλ){}function λ(δλ){}(function λ(δλ){})();"
}
iifes_returning_constants_keep_fargs_true: {
options = {
keep_fargs : true,
side_effects : true,
evaluate : true,
unused : true,
dead_code : true,
conditionals : true,
comparisons : true,
booleans : true,
if_return : true,
join_vars : true,
reduce_vars : true,
cascade : true,
}
input: {
(function(){ return -1.23; }());
console.log( function foo(){ return "okay"; }() );
console.log( function foo(x, y, z){ return 123; }() );
console.log( function(x, y, z){ return z; }() );
console.log( function(x, y, z){ if (x) return y; return z; }(1, 2, 3) );
console.log( function(x, y){ return x * y; }(2, 3) );
console.log( function(x, y){ return x * y; }(2, 3, a(), b()) );
}
expect: {
console.log("okay");
console.log(123);
console.log(void 0);
console.log(2);
console.log(6);
console.log((a(), b(), 6));
}
expect_stdout: true
}
iifes_returning_constants_keep_fargs_false: {
options = {
keep_fargs : false,
side_effects : true,
evaluate : true,
unused : true,
dead_code : true,
conditionals : true,
comparisons : true,
booleans : true,
if_return : true,
join_vars : true,
reduce_vars : true,
cascade : true,
}
input: {
(function(){ return -1.23; }());
console.log( function foo(){ return "okay"; }() );
console.log( function foo(x, y, z){ return 123; }() );
console.log( function(x, y, z){ return z; }() );
console.log( function(x, y, z){ if (x) return y; return z; }(1, 2, 3) );
console.log( function(x, y){ return x * y; }(2, 3) );
console.log( function(x, y){ return x * y; }(2, 3, a(), b()) );
}
expect: {
console.log("okay");
console.log(123);
console.log(void 0);
console.log(2);
console.log(6);
console.log((a(), b(), 6));
}
expect_stdout: true
}
issue_485_crashing_1530: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
(function(a) {
if (true) return;
var b = 42;
})(this);
}
expect: {
this, void 0;
}
}

View File

@@ -47,22 +47,6 @@ html_comment_in_greater_than_or_equal: {
expect_exact: "function f(a,b){return a-- >=b}";
}
html_comment_in_right_shift_assign: {
input: {
// Note: illegal javascript
function f(a, b) { return a-- >>= b; }
}
expect_exact: "function f(a,b){return a-- >>=b}";
}
html_comment_in_zero_fill_right_shift_assign: {
input: {
// Note: illegal javascript
function f(a, b) { return a-- >>>= b; }
}
expect_exact: "function f(a,b){return a-- >>>=b}";
}
html_comment_in_string_literal: {
input: {
function f() { return "<!--HTML-->comment in<!--string literal-->"; }

View File

@@ -39,7 +39,7 @@ non_hoisted_function_after_return_2a: {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false, passes: 2
collapse_vars: false, passes: 2, warnings: "verbose"
}
input: {
function foo(x) {
@@ -75,7 +75,7 @@ non_hoisted_function_after_return_2a: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]"
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
]
}
@@ -114,8 +114,5 @@ non_hoisted_function_after_return_2b: {
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:95,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:97,16]"
]
}

View File

@@ -195,11 +195,12 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
sequences: false,
}
input: {
var f = console.log;
var o = {
undefined : 3,
NaN : 4,
Infinity : 5,
}
};
if (o) {
f(undefined, void 0);
f(NaN, 0/0);
@@ -216,25 +217,25 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
}
}
expect: {
var o = {
var f = console.log, o = {
undefined : 3,
NaN : 4,
Infinity : 5
}
};
if (o) {
f(void 0, void 0);
f(NaN, NaN);
f(0/0, 0/0);
f(1/0, 1/0);
f(-(1/0), -(1/0));
f(NaN, NaN);
f(-1/0, -1/0);
f(0/0, 0/0);
}
with (o) {
f(undefined, void 0);
f(NaN, 0/0);
f(Infinity, 1/0);
f(-Infinity, -(1/0));
f(-Infinity, -1/0);
f(9 + undefined, 9 + void 0);
}
}
expect_stdout: true
}

View File

@@ -49,4 +49,3 @@ mangle_keep_fnames_true: {
}
}
}

View File

@@ -46,4 +46,5 @@ string_plus_optimization: {
}
foo();
}
expect_stdout: true
}

View File

@@ -14,6 +14,7 @@ issue_1321_no_debug: {
x["a"] = 2 * x.b;
console.log(x.b, x["a"]);
}
expect_stdout: true
}
issue_1321_debug: {
@@ -33,6 +34,7 @@ issue_1321_debug: {
x["_$foo$_"] = 2 * x.a;
console.log(x.a, x["_$foo$_"]);
}
expect_stdout: true
}
issue_1321_with_quoted: {
@@ -51,4 +53,5 @@ issue_1321_with_quoted: {
x["b"] = 2 * x.a;
console.log(x.a, x["b"]);
}
expect_stdout: true
}

View File

@@ -2,6 +2,7 @@
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true
}
@@ -19,12 +20,7 @@ unsafe_undefined: {
expect: {
function f(n) {
return function() {
if (a)
return b;
if (c)
return d;
else
return n;
return a ? b : c ? d : n;
};
}
}
@@ -32,6 +28,7 @@ unsafe_undefined: {
keep_fnames: {
options = {
conditionals: true,
if_return: true,
unsafe: true
}
@@ -57,12 +54,7 @@ keep_fnames: {
function n(n) {
return n * n;
}
if (a)
return b;
if (c)
return d;
else
return r;
return a ? b : c ? d : r;
};
}
}

View File

@@ -42,4 +42,5 @@ conditional_false_stray_else_in_loop: {
}
}
expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);"
expect_stdout: true
}

View File

@@ -0,0 +1,19 @@
inner_reference: {
options = {
side_effects: true,
}
input: {
!function f(a) {
return a && f(a - 1) + a;
}(42);
!function g(a) {
return a;
}(42);
}
expect: {
!function f(a) {
return a && f(a - 1) + a;
}(42);
!void 0;
}
}

View File

@@ -0,0 +1,99 @@
screw_ie8: {
options = {
screw_ie8: true,
}
mangle = {
screw_ie8: true,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
}
expect_exact: 'try{throw"foo"}catch(o){console.log(o)}'
expect_stdout: [
"foo"
]
}
support_ie8: {
options = {
screw_ie8: false,
}
mangle = {
screw_ie8: false,
}
input: {
try { throw "foo"; } catch (x) { console.log(x); }
}
expect_exact: 'try{throw"foo"}catch(x){console.log(x)}'
expect_stdout: "foo"
}
safe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: false,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}(1)());
}
expect: {
var a, c;
console.log(function(n) {
return function() {
return a ? b : c ? d : void 0;
};
}(1)());
}
expect_stdout: true
}
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
unsafe: true,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}()());
}
expect: {
var a, c;
console.log(function(n) {
return function() {
return a ? b : c ? d : n;
};
}()());
}
expect_stdout: true
}
runtime_error: {
input: {
const a = 1;
console.log(a++);
}
expect: {
const a = 1;
console.log(a++);
}
expect_stdout: true
}

View File

@@ -0,0 +1,56 @@
chained_evaluation_1: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = 1;
(function() {
var b = a, c;
c = f(b);
c.bar = b;
})();
})();
}
expect: {
(function() {
(function() {
var c;
c = f(1);
c.bar = 1;
})();
})();
}
}
chained_evaluation_2: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = "long piece of string";
(function() {
var b = a, c;
c = f(b);
c.bar = b;
})();
})();
}
expect: {
(function() {
var a = "long piece of string";
(function() {
var c;
c = f(a);
c.bar = a;
})();
})();
}
}

View File

@@ -0,0 +1,88 @@
issue_1639_1: {
options = {
booleans: true,
cascade: true,
conditionals: true,
evaluate: true,
join_vars: true,
loops: true,
sequences: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
var L1 = 5;
while (--L1 > 0) {
if ((--b), false) {
if (b) {
var ignore = 0;
}
}
}
console.log(a, b);
}
expect: {
for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
if (--b, !1) var ignore = 0;
console.log(a, b);
}
expect_stdout: true
}
issue_1639_2: {
options = {
booleans: true,
cascade: true,
conditionals: true,
evaluate: true,
join_vars: true,
sequences: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
function f19() {
if (++a, false)
if (a)
if (++a);
}
f19();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f19() {
++a, 1;
}
f19(),
console.log(a, b);
}
expect_stdout: true
}
issue_1639_3: {
options = {
booleans: true,
cascade: true,
conditionals: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
a++ && false && a ? 0 : 0;
console.log(a, b);
}
expect: {
var a = 100, b = 10;
a++,
console.log(a, b);
}
expect_stdout: true
}

View File

@@ -0,0 +1,45 @@
f7: {
options = {
booleans: true,
cascade: true,
collapse_vars: true,
comparisons: true,
conditionals: true,
dead_code: true,
drop_debugger: true,
evaluate: true,
hoist_funs: true,
if_return: true,
join_vars: true,
loops: true,
negate_iife: true,
passes: 3,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
beautify = {
beautify: true,
}
input: {
var a = 100, b = 10;
function f22464() {
var brake146670 = 5;
while (((b = a) ? !a : ~a ? null : b += a) && --brake146670 > 0) {
}
}
f22464();
console.log(a, b);
}
expect_exact: [
"var a = 100, b = 10;",
"",
"!function() {",
" for (;b = a, !1; ) ;",
"}(), console.log(a, b);",
]
expect_stdout: true
}

161
test/compress/issue-1673.js Normal file
View File

@@ -0,0 +1,161 @@
side_effects_catch: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
function g() {
try {
throw 0;
} catch (e) {
console.log("PASS");
}
}
g();
}
f();
}
expect: {
function f() {
(function() {
try {
throw 0;
} catch (e) {
console.log("PASS");
}
})();
}
f();
}
expect_stdout: "PASS"
}
side_effects_else: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
function g() {
if (x);
else console.log("PASS");
}
g();
}
f(0);
}
expect: {
function f(x) {
(function() {
if (x);
else console.log("PASS");
})();
}
f(0);
}
expect_stdout: "PASS"
}
side_effects_finally: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
function g() {
try {
x();
} catch (e) {
} finally {
console.log("PASS");
}
}
g();
}
f();
}
expect: {
function f() {
(function() {
try {
x();
} catch (e) {
} finally {
console.log("PASS");
}
})();
}
f();
}
expect_stdout: "PASS"
}
side_effects_label: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f(x) {
function g() {
L: {
console.log("PASS");
break L;
}
}
g();
}
f(0);
}
expect: {
function f(x) {
(function() {
L: {
console.log("PASS");
break L;
}
})();
}
f(0);
}
expect_stdout: "PASS"
}
side_effects_switch: {
options = {
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
function f() {
function g() {
switch (0) {
default:
case console.log("PASS"):
}
}
g();
}
f();
}
expect: {
function f() {
(function() {
switch (0) {
default:
case console.log("PASS"):
}
})();
}
f();
}
expect_stdout: "PASS"
}

347
test/compress/issue-1704.js Normal file
View File

@@ -0,0 +1,347 @@
mangle_catch: {
options = {
screw_ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: true,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(o){a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_ie8: {
options = {
screw_ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: false,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(args){a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_var: {
options = {
screw_ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: true,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(o){var a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_var_ie8: {
options = {
screw_ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: false,
toplevel: false,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var a="FAIL";try{throw 1}catch(args){var a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_toplevel: {
options = {
screw_ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: true,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_ie8_toplevel: {
options = {
screw_ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: false,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_var_toplevel: {
options = {
screw_ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: true,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_var_ie8_toplevel: {
options = {
screw_ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: false,
toplevel: true,
}
input: {
var a = "FAIL";
try {
throw 1;
} catch (args) {
var a = "PASS";
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_1: {
options = {
screw_ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: true,
toplevel: false,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_redef_1_ie8: {
options = {
screw_ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: false,
toplevel: false,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_redef_1_toplevel: {
options = {
screw_ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: true,
toplevel: true,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_1_ie8_toplevel: {
options = {
screw_ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: false,
toplevel: true,
}
input: {
var a = "PASS";
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_2: {
options = {
screw_ie8: true,
toplevel: false,
}
mangle = {
screw_ie8: true,
toplevel: false,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "undefined"
}
mangle_catch_redef_2_ie8: {
options = {
screw_ie8: false,
toplevel: false,
}
mangle = {
screw_ie8: false,
toplevel: false,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
expect_stdout: "undefined"
}
mangle_catch_redef_2_toplevel: {
options = {
screw_ie8: true,
toplevel: true,
}
mangle = {
screw_ie8: true,
toplevel: true,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}
mangle_catch_redef_2_ie8_toplevel: {
options = {
screw_ie8: false,
toplevel: true,
}
mangle = {
screw_ie8: false,
toplevel: true,
}
input: {
try {
throw "FAIL1";
} catch (a) {
var a = "FAIL2";
}
console.log(a);
}
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}

View File

@@ -0,0 +1,97 @@
function_iife_catch: {
mangle = {
screw_ie8: true,
}
input: {
function f(n) {
!function() {
try {
throw 0;
} catch (n) {
var a = 1;
console.log(n, a);
}
}();
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
function_iife_catch_ie8: {
mangle = {
screw_ie8: false,
}
input: {
function f(n) {
!function() {
try {
throw 0;
} catch (n) {
var a = 1;
console.log(n, a);
}
}();
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
function_catch_catch: {
mangle = {
screw_ie8: true,
}
input: {
var o = 0;
function f() {
try {
throw 1;
} catch (c) {
try {
throw 2;
} catch (o) {
var o = 3;
console.log(o);
}
}
console.log(o);
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_stdout: [
"3",
"undefined",
]
}
function_catch_catch_ie8: {
mangle = {
screw_ie8: false,
}
input: {
var o = 0;
function f() {
try {
throw 1;
} catch (c) {
try {
throw 2;
} catch (o) {
var o = 3;
console.log(o);
}
}
console.log(o);
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_stdout: [
"3",
"undefined",
]
}

View File

@@ -0,0 +1,55 @@
collapse: {
options = {
cascade: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f1() {
var a;
a = typeof b === 'function' ? b() : b;
return a !== undefined && c();
}
function f2(b) {
var a;
b = c();
a = typeof b === 'function' ? b() : b;
return 'stirng' == typeof a && d();
}
function f3(c) {
var a;
a = b(a / 2);
if (a < 0) {
a++;
++c;
return c / 2;
}
}
function f4(c) {
var a;
a = b(a / 2);
if (a < 0) {
a++;
c++;
return c / 2;
}
}
}
expect: {
function f1() {
return void 0 !== ('function' === typeof b ? b() : b) && c();
}
function f2(b) {
return b = c(), 'stirng' == typeof ('function' === typeof b ? b() : b) && d();
}
function f3(c) {
var a;
if ((a = b(a / 2)) < 0) return a++, ++c / 2;
}
function f4(c) {
var a;
if ((a = b(a / 2)) < 0) return a++, ++c / 2;
}
}
}

View File

@@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
}
expect: {
(1/0).toString();
NaN.toString(); // transformation to 0/0 dropped
(0/0).toString();
}
}
@@ -23,3 +23,105 @@ NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
NaN.toString();
}
}
beautify_off_1: {
options = {
evaluate: true,
}
beautify = {
beautify: false,
}
input: {
var NaN;
console.log(
null,
undefined,
Infinity,
NaN,
Infinity * undefined,
Infinity.toString(),
NaN.toString(),
(Infinity * undefined).toString()
);
}
expect_exact: "var NaN;console.log(null,void 0,1/0,NaN,0/0,(1/0).toString(),NaN.toString(),(0/0).toString());"
expect_stdout: true
}
beautify_off_2: {
options = {
evaluate: true,
}
beautify = {
beautify: false,
}
input: {
console.log(
null.toString(),
undefined.toString()
);
}
expect_exact: "console.log(null.toString(),(void 0).toString());"
}
beautify_on_1: {
options = {
evaluate: true,
}
beautify = {
beautify: true,
}
input: {
var NaN;
console.log(
null,
undefined,
Infinity,
NaN,
Infinity * undefined,
Infinity.toString(),
NaN.toString(),
(Infinity * undefined).toString()
);
}
expect_exact: [
"var NaN;",
"",
"console.log(null, void 0, 1 / 0, NaN, 0 / 0, (1 / 0).toString(), NaN.toString(), (0 / 0).toString());",
]
expect_stdout: true
}
beautify_on_2: {
options = {
evaluate: true,
}
beautify = {
beautify: true,
}
input: {
console.log(
null.toString(),
undefined.toString()
);
}
expect_exact: "console.log(null.toString(), (void 0).toString());"
}
issue_1724: {
input: {
var a = 0;
++a % Infinity | Infinity ? a++ : 0;
console.log(a);
}
expect_exact: "var a=0;++a%(1/0)|1/0?a++:0;console.log(a);"
expect_stdout: "2"
}
issue_1725: {
input: {
([].length === 0) % Infinity ? console.log("PASS") : console.log("FAIL");
}
expect_exact: '(0===[].length)%(1/0)?console.log("PASS"):console.log("FAIL");'
expect_stdout: "PASS"
}

320
test/compress/issue-640.js Normal file
View File

@@ -0,0 +1,320 @@
cond_5: {
options = {
conditionals: true,
expression: true,
}
input: {
if (some_condition()) {
if (some_other_condition()) {
do_something();
} else {
alternate();
}
} else {
alternate();
}
if (some_condition()) {
if (some_other_condition()) {
do_something();
}
}
}
expect: {
some_condition() && some_other_condition() ? do_something() : alternate();
if (some_condition() && some_other_condition()) do_something();
}
}
dead_code_const_annotation_regex: {
options = {
booleans : true,
conditionals : true,
dead_code : true,
evaluate : true,
expression : true,
loops : true,
}
input: {
var unused;
// @constraint this shouldn't be a constant
var CONST_FOO_ANN = false;
if (CONST_FOO_ANN) {
console.log("reachable");
}
}
expect: {
var unused;
var CONST_FOO_ANN = !1;
if (CONST_FOO_ANN) console.log('reachable');
}
expect_stdout: true
}
drop_console_2: {
options = {
drop_console: true,
expression: true,
}
input: {
console.log('foo');
console.log.apply(console, arguments);
}
expect: {
// with regular compression these will be stripped out as well
void 0;
void 0;
}
}
drop_value: {
options = {
expression: true,
side_effects: true,
}
input: {
(1, [2, foo()], 3, {a:1, b:bar()});
}
expect: {
foo(), {a:1, b:bar()};
}
}
wrongly_optimized: {
options = {
conditionals: true,
booleans: true,
evaluate: true,
expression: true,
}
input: {
function func() {
foo();
}
if (func() || true) {
bar();
}
}
expect: {
function func() {
foo();
}
// TODO: optimize to `func(), bar()`
if (func(), !0) bar();
}
}
negate_iife_1: {
options = {
expression: true,
negate_iife: true,
}
input: {
(function(){ stuff() })();
}
expect: {
(function(){ stuff() })();
}
}
negate_iife_3: {
options = {
conditionals: true,
expression: true,
negate_iife: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
}
negate_iife_3_off: {
options = {
conditionals: true,
expression: true,
negate_iife: false,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
}
negate_iife_4: {
options = {
conditionals: true,
expression: true,
negate_iife: true,
sequences: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
expect: {
(function(){ return t })() ? console.log(true) : console.log(false), function(){
console.log("something");
}();
}
}
negate_iife_5: {
options = {
conditionals: true,
expression: true,
negate_iife: true,
sequences: true,
}
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
(function(){ return t })() ? foo(true) : bar(false), function(){
console.log("something");
}();
}
}
negate_iife_5_off: {
options = {
conditionals: true,
expression: true,
negate_iife: false,
sequences: true,
};
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
(function(){ return t })() ? foo(true) : bar(false), function(){
console.log("something");
}();
}
}
issue_1254_negate_iife_true: {
options = {
expression: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()();
}
expect_exact: '(function(){return function(){console.log("test")}})()();'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
options = {
expression: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()()()()();
}
expect_exact: '(function(){return function(){console.log("test")}})()()()()();'
expect_stdout: true
}
conditional: {
options = {
expression: true,
pure_funcs: [ "pure" ],
side_effects: true,
}
input: {
pure(1 | a() ? 2 & b() : 7 ^ c());
pure(1 | a() ? 2 & b() : 5);
pure(1 | a() ? 4 : 7 ^ c());
pure(1 | a() ? 4 : 5);
pure(3 ? 2 & b() : 7 ^ c());
pure(3 ? 2 & b() : 5);
pure(3 ? 4 : 7 ^ c());
pure(3 ? 4 : 5);
}
expect: {
1 | a() ? b() : c();
1 | a() && b();
1 | a() || c();
a();
3 ? b() : c();
3 && b();
3 || c();
pure(3 ? 4 : 5);
}
}
limit_1: {
options = {
expression: true,
sequences: 3,
}
input: {
a;
b;
c;
d;
e;
f;
g;
h;
i;
j;
k;
}
expect: {
// Turned into a single return statement
// so it can no longer be split into lines
a,b,c,d,e,f,g,h,i,j,k;
}
}
iife: {
options = {
expression: true,
sequences: true,
}
input: {
x = 42;
(function a() {})();
!function b() {}();
~function c() {}();
+function d() {}();
-function e() {}();
void function f() {}();
typeof function g() {}();
}
expect: {
x = 42, function a() {}(), function b() {}(), function c() {}(),
function d() {}(), function e() {}(), function f() {}(), typeof function g() {}();
}
}

View File

@@ -29,4 +29,5 @@ dont_mangle_arguments: {
})(5,6,7);
}
expect_exact: "(function(){var arguments=arguments,o=9;console.log(o,arguments)})(5,6,7);"
expect_stdout: true
}

View File

@@ -50,6 +50,7 @@ this_binding_conditionals: {
this_binding_collapse_vars: {
options = {
collapse_vars: true,
toplevel: true,
};
input: {
var c = a; c();

View File

@@ -42,6 +42,7 @@ eval_collapse_vars: {
eval("console.log(a);");
})(eval);
}
expect_stdout: true
}
eval_unused: {

View File

@@ -9,6 +9,7 @@ labels_1: {
expect: {
foo || console.log("bar");
}
expect_stdout: true
}
labels_2: {
@@ -40,6 +41,7 @@ labels_3: {
for (var i = 0; i < 5; ++i)
i < 3 || console.log(i);
}
expect_stdout: true
}
labels_4: {
@@ -54,6 +56,7 @@ labels_4: {
for (var i = 0; i < 5; ++i)
i < 3 || console.log(i);
}
expect_stdout: true
}
labels_5: {

View File

@@ -166,6 +166,7 @@ keep_collapse_const_in_own_block_scope: {
console.log(i);
console.log(c);
}
expect_stdout: true
}
keep_collapse_const_in_own_block_scope_2: {
@@ -186,6 +187,7 @@ keep_collapse_const_in_own_block_scope_2: {
console.log(i);
console.log(c);
}
expect_stdout: true
}
evaluate: {
@@ -213,6 +215,246 @@ evaluate: {
a();
for(;;)
c();
d();
// rule disabled due to issue_1532
do d(); while (false);
}
}
issue_1532: {
options = {
evaluate: true,
loops: true,
}
input: {
function f(x, y) {
do {
if (x) break;
foo();
} while (false);
}
}
expect: {
function f(x, y) {
do {
if (x) break;
foo();
} while (false);
}
}
}
issue_186: {
beautify = {
beautify: false,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo())do{do{alert(x)}while(--x)}while(x);else bar();'
}
issue_186_ie8: {
beautify = {
beautify: false,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else bar();'
}
issue_186_beautify: {
beautify = {
beautify: true,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) do {',
' do {',
' alert(x);',
' } while (--x);',
'} while (x); else bar();',
]
}
issue_186_beautify_ie8: {
beautify = {
beautify: true,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else bar();',
]
}
issue_186_bracketize: {
beautify = {
beautify: false,
bracketize: true,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_bracketize_ie8: {
beautify = {
beautify: false,
bracketize: true,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_beautify_bracketize: {
beautify = {
beautify: true,
bracketize: true,
screw_ie8: true,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else {',
' bar();',
'}',
]
}
issue_186_beautify_bracketize_ie8: {
beautify = {
beautify: true,
bracketize: true,
screw_ie8: false,
}
input: {
var x = 3;
if (foo())
do
do
alert(x);
while (--x);
while (x);
else
bar();
}
expect_exact: [
'var x = 3;',
'',
'if (foo()) {',
' do {',
' do {',
' alert(x);',
' } while (--x);',
' } while (x);',
'} else {',
' bar();',
'}',
]
}
issue_1648: {
options = {
join_vars: true,
loops: true,
passes: 2,
sequences: true,
unused: true,
}
input: {
function f() {
x();
var b = 1;
while (1);
}
}
expect_exact: "function f(){for(x();1;);}"
}

View File

@@ -7,7 +7,13 @@ too_short: {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{\nc:42,\nd:a(),\ne:"foo"}}'
expect_exact: [
'function f(a){',
'return{',
'c:42,',
'd:a(),',
'e:"foo"}}',
]
expect_warnings: [
"WARN: Output exceeds 10 characters"
]
@@ -22,7 +28,12 @@ just_enough: {
return { c: 42, d: a(), e: "foo"};
}
}
expect_exact: 'function f(a){\nreturn{c:42,\nd:a(),e:"foo"}\n}'
expect_exact: [
'function f(a){',
'return{c:42,',
'd:a(),e:"foo"}',
'}',
]
expect_warnings: [
]
}

View File

@@ -32,16 +32,58 @@ negate_iife_2: {
}
}
negate_iife_2_side_effects: {
options = {
negate_iife: true,
side_effects: true,
}
input: {
(function(){ return {} })().x = 10; // should not transform this one
}
expect: {
(function(){ return {} })().x = 10;
}
}
negate_iife_3: {
options = {
negate_iife: true,
conditionals: true
};
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true);
}
}
negate_iife_3_evaluate: {
options = {
conditionals: true,
evaluate: true,
negate_iife: true,
}
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true);
console.log(true);
}
expect_stdout: true
}
negate_iife_3_side_effects: {
options = {
conditionals: true,
negate_iife: true,
side_effects: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true);
}
}
@@ -50,12 +92,27 @@ negate_iife_3_off: {
negate_iife: false,
conditionals: true,
};
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return t }() ? console.log(false) : console.log(true);
}
}
negate_iife_3_off_evaluate: {
options = {
conditionals: true,
evaluate: true,
negate_iife: false,
}
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true);
console.log(true);
}
expect_stdout: true
}
negate_iife_4: {
@@ -65,13 +122,13 @@ negate_iife_4: {
sequences: true
};
input: {
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
expect: {
!function(){ return true }() ? console.log(false) : console.log(true), function(){
!function(){ return t }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
@@ -86,7 +143,7 @@ sequence_off: {
};
input: {
function f() {
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
@@ -95,19 +152,19 @@ sequence_off: {
(function(){
console.log("something");
})();
(function(){ return true })() ? console.log(true) : console.log(false);
(function(){ return t })() ? console.log(true) : console.log(false);
}
}
expect: {
function f() {
!function(){ return true }() ? console.log(false) : console.log(true), function(){
!function(){ return t }() ? console.log(false) : console.log(true), function(){
console.log("something");
}();
}
function g() {
(function(){
console.log("something");
})(), function(){ return true }() ? console.log(true) : console.log(false);
})(), function(){ return t }() ? console.log(true) : console.log(false);
}
}
}
@@ -119,7 +176,7 @@ negate_iife_5: {
conditionals: true,
};
input: {
if ((function(){ return true })()) {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
@@ -129,7 +186,7 @@ negate_iife_5: {
})();
}
expect: {
!function(){ return true }() ? bar(false) : foo(true), function(){
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
@@ -142,7 +199,7 @@ negate_iife_5_off: {
conditionals: true,
};
input: {
if ((function(){ return true })()) {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
@@ -152,7 +209,7 @@ negate_iife_5_off: {
})();
}
expect: {
!function(){ return true }() ? bar(false) : foo(true), function(){
!function(){ return t }() ? bar(false) : foo(true), function(){
console.log("something");
}();
}
@@ -188,6 +245,7 @@ negate_iife_nested: {
}(7);
}).f();
}
expect_stdout: true
}
negate_iife_nested_off: {
@@ -220,6 +278,7 @@ negate_iife_nested_off: {
})(7);
}).f();
}
expect_stdout: true
}
negate_iife_issue_1073: {
@@ -244,6 +303,7 @@ negate_iife_issue_1073: {
};
}(7))();
}
expect_stdout: true
}
issue_1254_negate_iife_false: {
@@ -258,6 +318,7 @@ issue_1254_negate_iife_false: {
})()();
}
expect_exact: '(function(){return function(){console.log("test")}})()();'
expect_stdout: true
}
issue_1254_negate_iife_true: {
@@ -272,6 +333,7 @@ issue_1254_negate_iife_true: {
})()();
}
expect_exact: '!function(){return function(){console.log("test")}}()();'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
@@ -286,12 +348,14 @@ issue_1254_negate_iife_nested: {
})()()()()();
}
expect_exact: '!function(){return function(){console.log("test")}}()()()()();'
expect_stdout: true
}
issue_1288: {
options = {
negate_iife: true,
conditionals: true,
negate_iife: true,
side_effects: false,
};
input: {
if (w) ;
@@ -311,12 +375,44 @@ issue_1288: {
})(0);
}
expect: {
w || function f() {}();
x || function() {
w || !function f() {}();
x || !function() {
x = {};
}();
y ? function() {}() : function(z) {
y ? !function() {}() : !function(z) {
return z;
}(0);
}
}
issue_1288_side_effects: {
options = {
conditionals: true,
negate_iife: true,
side_effects: true,
}
input: {
if (w) ;
else {
(function f() {})();
}
if (!x) {
(function() {
x = {};
})();
}
if (y)
(function() {})();
else
(function(z) {
return z;
})(0);
}
expect: {
w;
x || function() {
x = {};
}();
y;
}
}

View File

@@ -17,3 +17,188 @@ hex_numbers_in_parentheses_for_prototype_functions: {
}
expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);"
}
comparisons: {
options = {
comparisons: true,
}
input: {
console.log(
~x === 42,
x % n === 42
);
}
expect: {
console.log(
42 == ~x,
x % n == 42
);
}
}
evaluate_1: {
options = {
evaluate: true,
unsafe_math: false,
}
input: {
console.log(
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 + (2 + ~x + 3),
-y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3)
);
}
expect: {
console.log(
x + 1 + 2,
1 * x * 2,
+x + 1 + 2,
1 + x + 2 + 3,
3 | x,
1 + x-- + 2 + 3,
x*y + 2 + 1 + 3,
1 + (2 + x + 3),
2 + ~x + 3 + 1,
-y + (2 + ~x + 3),
0 & x,
2 + (x |= 0) + 3 + 1
);
}
}
evaluate_2: {
options = {
evaluate: true,
unsafe_math: true,
}
input: {
console.log(
x + 1 + 2,
x * 1 * 2,
+x + 1 + 2,
1 + x + 2 + 3,
1 | x | 2 | 3,
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3)
);
}
expect: {
console.log(
x + 1 + 2,
2 * x,
3 + +x,
1 + x + 2 + 3,
3 | x,
6 + x--,
6 + x*y,
1 + (2 + x + 3),
0 & x,
6 + (x |= 0)
);
}
}
evaluate_3: {
options = {
evaluate: true,
unsafe: true,
unsafe_math: true,
}
input: {
console.log(1 + Number(x) + 2);
}
expect: {
console.log(3 + +x);
}
}
evaluate_4: {
options = {
evaluate: true,
}
input: {
console.log(
1+ +a,
+a+1,
1+-a,
-a+1,
+a+ +b,
+a+-b,
-a+ +b,
-a+-b
);
}
expect: {
console.log(
+a+1,
+a+1,
1-a,
1-a,
+a+ +b,
+a-b,
-a+ +b,
-a-b
);
}
}
issue_1710: {
options = {
evaluate: true,
}
input: {
var x = {};
console.log((x += 1) + -x);
}
expect: {
var x = {};
console.log((x += 1) + -x);
}
expect_stdout: true
}
unary_binary_parenthesis: {
input: {
var v = [ 0, 1, NaN, Infinity, null, undefined, true, false, "", "foo", /foo/ ];
v.forEach(function(x) {
v.forEach(function(y) {
console.log(
+(x*y),
+(x/y),
+(x%y),
-(x*y),
-(x/y),
-(x%y)
);
});
});
}
expect: {
var v = [ 0, 1, 0/0, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
v.forEach(function(x) {
v.forEach(function(y) {
console.log(
+x*y,
+x/y,
+x%y,
-x*y,
-x/y,
-x%y
);
});
});
}
expect_stdout: true
}

View File

@@ -77,7 +77,7 @@ sub_properties: {
a[3.14] = 3;
a.if = 4;
a["foo bar"] = 5;
a[NaN] = 6;
a[0/0] = 6;
a[null] = 7;
a[void 0] = 8;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +1,49 @@
do_screw: {
options = { screw_ie8: true };
options = {
screw_ie8: true,
}
beautify = {
screw_ie8: true,
ascii_only: true
};
input: f("\v");
expect_exact: 'f("\\v");';
ascii_only: true,
}
input: {
f("\v");
}
expect_exact: 'f("\\v");'
}
dont_screw: {
options = { screw_ie8: false };
beautify = { screw_ie8: false, ascii_only: true };
options = {
screw_ie8: false,
}
beautify = {
screw_ie8: false,
ascii_only: true,
}
input: {
f("\v");
}
expect_exact: 'f("\\x0B");'
}
input: f("\v");
expect_exact: 'f("\\x0B");';
do_screw_constants: {
options = {
screw_ie8: true,
}
input: {
f(undefined, Infinity);
}
expect_exact: "f(void 0,1/0);"
}
dont_screw_constants: {
options = {
screw_ie8: false,
}
input: {
f(undefined, Infinity);
}
expect_exact: "f(undefined,Infinity);"
}
do_screw_try_catch: {
@@ -46,8 +75,6 @@ do_screw_try_catch: {
}
dont_screw_try_catch: {
// This test is known to generate incorrect code for screw_ie8=false.
// Update expected result in the event this bug is ever fixed.
options = { screw_ie8: false };
mangle = { screw_ie8: false };
beautify = { screw_ie8: false };
@@ -64,11 +91,11 @@ dont_screw_try_catch: {
}
expect: {
bad = function(n){
return function(n){
return function(t){
try{
t()
} catch(t) {
n(t)
n()
} catch(n) {
t(n)
}
}
};
@@ -101,11 +128,10 @@ do_screw_try_catch_undefined: {
return void 0===o
}
}
expect_stdout: true
}
dont_screw_try_catch_undefined: {
// This test is known to generate incorrect code for screw_ie8=false.
// Update expected result in the event this bug is ever fixed.
options = { screw_ie8: false };
mangle = { screw_ie8: false };
beautify = { screw_ie8: false };
@@ -121,14 +147,87 @@ dont_screw_try_catch_undefined: {
};
}
expect: {
function a(o){
function a(n){
try{
throw "Stuff"
} catch (n) {
console.log("caught: "+n)
} catch (undefined) {
console.log("caught: " + undefined)
}
console.log("undefined is " + n);
return o === n
console.log("undefined is " + undefined);
return n === undefined
}
}
expect_stdout: true
}
reduce_vars: {
options = {
evaluate: true,
reduce_vars: true,
screw_ie8: false,
unused: true,
}
mangle = {
screw_ie8: false,
}
input: {
function f() {
var a;
try {
x();
} catch (a) {
y();
}
alert(a);
}
}
expect: {
function f() {
var t;
try {
x();
} catch (t) {
y();
}
alert(t);
}
}
}
issue_1586_1: {
options = {
screw_ie8: false,
}
mangle = {
screw_ie8: false,
}
input: {
function f() {
try {
x();
} catch (err) {
console.log(err.message);
}
}
}
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
}
issue_1586_2: {
options = {
screw_ie8: true,
}
mangle = {
screw_ie8: true,
}
input: {
function f() {
try {
x();
} catch (err) {
console.log(err.message);
}
}
}
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
}

View File

@@ -86,6 +86,7 @@ make_sequences_4: {
switch (x = 5, y) {}
with (x = 5, obj);
}
expect_stdout: true
}
lift_sequences_1: {
@@ -103,15 +104,18 @@ lift_sequences_1: {
lift_sequences_2: {
options = { sequences: true, evaluate: true };
input: {
var foo, bar;
var foo = 1, bar;
foo.x = (foo = {}, 10);
bar = (bar = {}, 10);
console.log(foo, bar);
}
expect: {
var foo, bar;
var foo = 1, bar;
foo.x = (foo = {}, 10),
bar = {}, bar = 10;
bar = {}, bar = 10,
console.log(foo, bar);
}
expect_stdout: true
}
lift_sequences_3: {
@@ -138,6 +142,23 @@ lift_sequences_4: {
}
}
lift_sequences_5: {
options = {
sequences: true,
}
input: {
var a = 2, b;
a *= (b, a = 4, 3);
console.log(a);
}
expect: {
var a = 2, b;
b, a *= (a = 4, 3),
console.log(a);
}
expect_stdout: "6"
}
for_sequences: {
options = { sequences: true };
input: {
@@ -230,6 +251,7 @@ negate_iife_for: {
for (!function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 5; i++) console.log(i);
}
expect_stdout: true
}
iife: {
@@ -248,6 +270,173 @@ iife: {
}
expect: {
x = 42, function a() {}(), function b() {}(), function c() {}(),
function d() {}(), function e() {}(), function f() {}(), function g() {}()
function d() {}(), function e() {}(), function f() {}(), function g() {}();
}
}
unsafe_undefined: {
options = {
conditionals: true,
if_return: true,
sequences: true,
side_effects: true,
unsafe: true,
}
input: {
function f(undefined) {
if (a)
return b;
if (c)
return d;
}
function g(undefined) {
if (a)
return b;
if (c)
return d;
e();
}
}
expect: {
function f(undefined) {
return a ? b : c ? d : undefined;
}
function g(undefined) {
return a ? b : c ? d : void e();
}
}
}
issue_1685: {
options = {
cascade: true,
side_effects: true,
}
input: {
var a = 100, b = 10;
function f() {
var a = (a--, delete a && --b);
}
f();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f() {
var a = (a--, delete a && --b);
}
f();
console.log(a, b);
}
expect_stdout: true
}
func_def_1: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
return f = 0, !!f;
}
console.log(f());
}
expect: {
function f() {
return !!(f = 0);
}
console.log(f());
}
expect_stdout: "false"
}
func_def_2: {
options = {
cascade: true,
side_effects: true,
}
input: {
console.log(function f() {
return f = 0, !!f;
}());
}
expect: {
console.log(function f() {
return f = 0, !!f;
}());
}
expect_stdout: "true"
}
func_def_3: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
function g() {}
return g = 0, !!g;
}
console.log(f());
}
expect: {
function f() {
function g() {}
return !!(g = 0);
}
console.log(f());
}
expect_stdout: "false"
}
func_def_4: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
function g() {
return g = 0, !!g;
}
return g();
}
console.log(f());
}
expect: {
function f() {
function g() {
return !!(g = 0);
}
return g();
}
console.log(f());
}
expect_stdout: "false"
}
func_def_5: {
options = {
cascade: true,
side_effects: true,
}
input: {
function f() {
return function g(){
return g = 0, !!g;
}();
}
console.log(f());
}
expect: {
function f() {
return function g(){
return g = 0, !!g;
}();
}
console.log(f());
}
expect_stdout: "true"
}

View File

@@ -258,3 +258,466 @@ keep_default: {
}
}
}
issue_1663: {
options = {
dead_code: true,
evaluate: true,
}
input: {
var a = 100, b = 10;
function f() {
switch (1) {
case 1:
b = a++;
return ++b;
default:
var b;
}
}
f();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f() {
var b;
b = a++;
return ++b;
}
f();
console.log(a, b);
}
expect_stdout: true
}
drop_case: {
options = {
dead_code: true,
}
input: {
switch (foo) {
case 'bar': baz(); break;
case 'moo':
break;
}
}
expect: {
switch (foo) {
case 'bar': baz();
}
}
}
keep_case: {
options = {
dead_code: true,
}
input: {
switch (foo) {
case 'bar': baz(); break;
case moo:
break;
}
}
expect: {
switch (foo) {
case 'bar': baz(); break;
case moo:
}
}
}
issue_376: {
options = {
dead_code: true,
evaluate: true,
}
input: {
switch (true) {
case boolCondition:
console.log(1);
break;
case false:
console.log(2);
break;
}
}
expect: {
switch (true) {
case boolCondition:
console.log(1);
}
}
}
issue_441_1: {
options = {
dead_code: true,
}
input: {
switch (foo) {
case bar:
qux();
break;
case baz:
qux();
break;
default:
qux();
break;
}
}
expect: {
switch (foo) {
case bar:
case baz:
default:
qux();
}
}
}
issue_441_2: {
options = {
dead_code: true,
}
input: {
switch (foo) {
case bar:
// TODO: Fold into the case below
qux();
break;
case fall:
case baz:
qux();
break;
default:
qux();
break;
}
}
expect: {
switch (foo) {
case bar:
qux();
break;
case fall:
case baz:
default:
qux();
}
}
}
issue_1674: {
options = {
dead_code: true,
evaluate: true,
}
input: {
switch (0) {
default:
console.log("FAIL");
break;
case 0:
console.log("PASS");
break;
}
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_1679: {
options = {
dead_code: true,
evaluate: true,
}
input: {
var a = 100, b = 10;
function f() {
switch (--b) {
default:
case !function x() {}:
break;
case b--:
switch (0) {
default:
case a--:
}
break;
case (a++):
break;
}
}
f();
console.log(a, b);
}
expect: {
var a = 100, b = 10;
function f() {
switch (--b) {
default:
case !function x() {}:
break;
case b--:
switch (0) {
default:
case a--:
}
break;
case (a++):
}
}
f();
console.log(a, b);
}
expect_stdout: true
}
issue_1680_1: {
options = {
dead_code: true,
evaluate: true,
}
input: {
function f(x) {
console.log(x);
return x + 1;
}
switch (2) {
case f(0):
case f(1):
f(2);
case 2:
case f(3):
case f(4):
f(5);
}
}
expect: {
function f(x) {
console.log(x);
return x + 1;
}
switch (2) {
case f(0):
case f(1):
f(2);
case 2:
f(5);
}
}
expect_stdout: [
"0",
"1",
"2",
"5",
]
}
issue_1680_2: {
options = {
dead_code: true,
}
input: {
var a = 100, b = 10;
switch (b) {
case a--:
break;
case b:
var c;
break;
case a:
break;
case a--:
break;
}
console.log(a, b);
}
expect: {
var a = 100, b = 10;
switch (b) {
case a--:
break;
case b:
var c;
break;
case a:
case a--:
}
console.log(a, b);
}
expect_stdout: true
}
issue_1690_1: {
options = {
dead_code: true,
}
input: {
switch (console.log("PASS")) {}
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_1690_2: {
options = {
dead_code: false,
}
input: {
switch (console.log("PASS")) {}
}
expect: {
switch (console.log("PASS")) {}
}
expect_stdout: "PASS"
}
if_switch_typeof: {
options = {
conditionals: true,
dead_code: true,
side_effects: true,
}
input: {
if (a) switch(typeof b) {}
}
expect: {
a;
}
}
issue_1698: {
options = {
side_effects: true,
}
input: {
var a = 1;
!function() {
switch (a++) {}
}();
console.log(a);
}
expect: {
var a = 1;
!function() {
switch (a++) {}
}();
console.log(a);
}
expect_stdout: "2"
}
issue_1705_1: {
options = {
dead_code: true,
}
input: {
var a = 0;
switch (a) {
default:
console.log("FAIL");
case 0:
break;
}
}
expect: {
var a = 0;
switch (a) {
default:
console.log("FAIL");
case 0:
}
}
expect_stdout: true
}
issue_1705_2: {
options = {
dead_code: true,
evaluate: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
switch (a) {
default:
console.log("FAIL");
case 0:
break;
}
}
expect: {
}
expect_stdout: true
}
issue_1705_3: {
options = {
dead_code: true,
}
input: {
switch (a) {
case 0:
break;
default:
break;
}
}
expect: {
a;
}
expect_stdout: true
}
beautify: {
beautify = {
beautify: true,
}
input: {
switch (a) {
case 0:
case 1:
break;
case 2:
default:
}
switch (b) {
case 3:
foo();
bar();
default:
break;
}
}
expect_exact: [
"switch (a) {",
" case 0:",
" case 1:",
" break;",
"",
" case 2:",
" default:",
"}",
"",
"switch (b) {",
" case 3:",
" foo();",
" bar();",
"",
" default:",
" break;",
"}",
]
}

130
test/compress/transform.js Normal file
View File

@@ -0,0 +1,130 @@
booleans_evaluate: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(typeof void 0 != "undefined");
console.log(1 == 1, 1 === 1)
console.log(1 != 1, 1 !== 1)
}
expect: {
console.log(!1);
console.log(!0, !0);
console.log(!1, !1);
}
expect_stdout: true
}
booleans_global_defs: {
options = {
booleans: true,
evaluate: true,
global_defs: {
A: true,
},
}
input: {
console.log(A == 1);
}
expect: {
console.log(!0);
}
}
condition_evaluate: {
options = {
booleans: true,
dead_code: false,
evaluate: true,
loops: false,
}
input: {
while (1 === 2);
for (; 1 == true;);
if (void 0 == null);
}
expect: {
while (!1);
for (; !0;);
if (!0);
}
}
if_else_empty: {
options = {
conditionals: true,
}
input: {
if ({} ? a : b); else {}
}
expect: {
!{} ? b : a;
}
}
label_if_break: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
}
input: {
L: if (true) {
a;
break L;
}
}
expect: {
a;
}
}
while_if_break: {
options = {
conditionals: true,
loops: true,
sequences: true,
}
input: {
while (a) {
if (b) if(c) d;
if (e) break;
}
}
expect: {
for(; a && (b && c && d, !e););
}
}
if_return: {
options = {
booleans: true,
conditionals: true,
if_return: true,
sequences: true,
}
input: {
function f(w, x, y, z) {
if (x) return;
if (w) {
if (y) return;
} else if (z) return;
if (x == y) return true;
if (x) w();
if (y) z();
return true;
}
}
expect: {
function f(w, x, y, z) {
if (!x) {
if (w) {
if (y) return;
} else if (z) return;
return x == y || (x && w(), y && z(), !0);
}
}
}
}

View File

@@ -48,3 +48,15 @@ typeof_in_boolean_context: {
foo();
}
}
issue_1668: {
options = {
booleans: true,
}
input: {
if (typeof bar);
}
expect: {
if (!0);
}
}

View File

@@ -0,0 +1 @@
console.log(1 || 5--);

View File

@@ -0,0 +1 @@
console.log(2 || (Math.random() /= 2));

View File

@@ -0,0 +1 @@
console.log(3 || ++this);

View File

@@ -0,0 +1 @@
for (var i = 0; i < 1; i++)

View File

@@ -0,0 +1 @@
console.log(x);

View File

@@ -82,7 +82,7 @@ describe("bin/uglifyjs", function () {
});
});
it("Should work with --keep-fnames (mangle & compress)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c';
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
exec(command, function (err, stdout) {
if (err) throw err;
@@ -152,7 +152,7 @@ describe("bin/uglifyjs", function () {
});
});
it("Should process inline source map", function(done) {
var command = uglifyjscmd + ' test/input/issue-520/input.js -cm toplevel --in-source-map inline --source-map-inline';
var command = uglifyjscmd + ' test/input/issue-520/input.js -mc toplevel --in-source-map inline --source-map-inline';
exec(command, function (err, stdout) {
if (err) throw err;
@@ -238,4 +238,72 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should fail with a missing loop body", function(done) {
var command = uglifyjscmd + ' test/input/invalid/loop-no-body.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/loop-no-body.js:2,0");
assert.strictEqual(lines[1], "for (var i = 0; i < 1; i++) ");
assert.strictEqual(lines[2], " ^");
assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)");
done();
});
});
it("Should support hyphen as shorthand", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep-fnames=true';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should throw syntax error (5--)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_1.js:1,18",
"console.log(1 || 5--);",
" ^",
"SyntaxError: Invalid use of -- operator"
].join("\n"));
done();
});
});
it("Should throw syntax error (Math.random() /= 2)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_2.js:1,32",
"console.log(2 || (Math.random() /= 2));",
" ^",
"SyntaxError: Invalid assignment"
].join("\n"));
done();
});
});
it("Should throw syntax error (++this)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
"Parse error at test/input/invalid/assign_3.js:1,18",
"console.log(3 || ++this);",
" ^",
"SyntaxError: Invalid use of ++ operator"
].join("\n"));
done();
});
});
});

View File

@@ -72,4 +72,12 @@ describe("comment filters", function() {
assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}");
assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}");
});
it("Should handle shebang and preamble correctly", function() {
var code = UglifyJS.minify("#!/usr/bin/node\nvar x = 10;", {
fromString: true,
output: { preamble: "/* Build */" }
}).code;
assert.strictEqual(code, "#!/usr/bin/node\n/* Build */\nvar x=10;");
})
});

View File

@@ -176,7 +176,7 @@ describe("Directives", function() {
});
it("Should test EXPECT_DIRECTIVE RegExp", function() {
var tests = [
[
["", true],
["'test';", true],
["'test';;", true],
@@ -185,11 +185,12 @@ describe("Directives", function() {
["'tests'; \n\t", true],
["'tests';\n\n", true],
["\n\n\"use strict\";\n\n", true]
];
for (var i = 0; i < tests.length; i++) {
assert.strictEqual(uglify.EXPECT_DIRECTIVE.test(tests[i][0]), tests[i][1], tests[i][0]);
}
].forEach(function(test) {
var out = uglify.OutputStream();
out.print(test[0]);
out.print_string("", null, true);
assert.strictEqual(out.get() === test[0] + ';""', test[1], test[0]);
});
});
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {

View File

@@ -1,19 +1,16 @@
var Uglify = require('../../');
var assert = require("assert");
var path = require("path");
describe("minify() with input file globs", function() {
it("minify() with one input file glob string.", function() {
var result = Uglify.minify("test/input/issue-1242/foo.*", {
compress: { collapse_vars: true }
});
var result = Uglify.minify("test/input/issue-1242/foo.*");
assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
});
it("minify() with an array of one input file glob.", function() {
var result = Uglify.minify([
"test/input/issue-1242/b*.es5",
], {
compress: { collapse_vars: true }
});
]);
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}');
});
it("minify() with an array of multiple input file globs.", function() {
@@ -21,8 +18,41 @@ describe("minify() with input file globs", function() {
"test/input/issue-1242/???.es5",
"test/input/issue-1242/*.js",
], {
compress: { collapse_vars: true }
compress: { toplevel: true }
});
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}function foo(n){print("Foo:",2*n)}var print=console.log.bind(console);print("qux",bar(3),baz(12)),foo(11);');
assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);');
});
it("should throw with non-matching glob string", function() {
var glob = "test/input/issue-1242/blah.*";
assert.strictEqual(Uglify.simple_glob(glob).length, 1);
assert.strictEqual(Uglify.simple_glob(glob)[0], glob);
assert.throws(function() {
Uglify.minify(glob);
}, "should throw file not found");
});
it('"?" in glob string should not match "/"', function() {
var glob = "test/input?issue-1242/foo.*";
assert.strictEqual(Uglify.simple_glob(glob).length, 1);
assert.strictEqual(Uglify.simple_glob(glob)[0], glob);
assert.throws(function() {
Uglify.minify(glob);
}, "should throw file not found");
});
it("should handle special characters in glob string", function() {
var result = Uglify.minify("test/input/issue-1632/^{*}[???](*)+$.??");
assert.strictEqual(result.code, "console.log(x);");
});
it("should handle array of glob strings - matching and otherwise", function() {
var dir = "test/input/issue-1242";
var matches = Uglify.simple_glob([
path.join(dir, "b*.es5"),
path.join(dir, "z*.es5"),
path.join(dir, "*.js"),
]);
assert.strictEqual(matches.length, 4);
assert.strictEqual(matches[0], path.join(dir, "bar.es5"));
assert.strictEqual(matches[1], path.join(dir, "baz.es5"));
assert.strictEqual(matches[2], path.join(dir, "z*.es5"));
assert.strictEqual(matches[3], path.join(dir, "qux.js"));
});
});

View File

@@ -78,6 +78,7 @@ describe("minify", function() {
});
it("Should process inline source map", function() {
var code = Uglify.minify("./test/input/issue-520/input.js", {
compress: { toplevel: true },
inSourceMap: "inline",
sourceMapInline: true
}).code + "\n";
@@ -155,7 +156,7 @@ describe("minify", function() {
assert.strictEqual(code, "// comment1 comment2\nbar();");
});
it("should not drop #__PURE__ hint if function is retained", function() {
var result = Uglify.minify("var a = /*#__PURE__*/(function(){return 1})();", {
var result = Uglify.minify("var a = /*#__PURE__*/(function(){ foo(); })();", {
fromString: true,
output: {
comments: "all",
@@ -163,7 +164,7 @@ describe("minify", function() {
}
});
var code = result.code;
assert.strictEqual(code, "var a=/*#__PURE__*/function(){return 1}();");
assert.strictEqual(code, "var a=/*#__PURE__*/function(){foo()}();");
})
});

54
test/mocha/release.js Normal file
View File

@@ -0,0 +1,54 @@
var assert = require("assert");
var spawn = require("child_process").spawn;
if (!process.env.UGLIFYJS_TEST_ALL) return;
function run(command, args, done) {
var id = setInterval(function() {
process.stdout.write("\0");
}, 5 * 60 * 1000);
spawn(command, args, {
stdio: "ignore"
}).on("exit", function(code) {
clearInterval(id);
assert.strictEqual(code, 0);
done();
});
}
describe("test/benchmark.js", function() {
this.timeout(5 * 60 * 1000);
[
"-b",
"-b bracketize",
"-m",
"-mc passes=3",
"-mc passes=3,toplevel",
"-mc passes=3,unsafe",
"-mc keep_fargs=false,passes=3",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].forEach(function(options) {
it("Should pass with options " + options, function(done) {
var args = options.split(/ /);
args.unshift("test/benchmark.js");
run(process.argv[0], args, done);
});
});
});
describe("test/jetstream.js", function() {
this.timeout(20 * 60 * 1000);
it("Should install phantomjs-prebuilt", function(done) {
run("npm", ["install", "phantomjs-prebuilt@2.1.14"], done);
});
[
"-mc warnings=false",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto,warnings=false",
].forEach(function(options) {
it("Should pass with options " + options, function(done) {
var args = options.split(/ /);
args.unshift("test/jetstream.js");
run(process.argv[0], args, done);
});
});
});

View File

@@ -5,7 +5,7 @@ var UglifyJS = require(".."),
escodegen = require("escodegen"),
esfuzz = require("esfuzz"),
estraverse = require("estraverse"),
prefix = Array(20).join("\b") + " ";
prefix = "\r ";
// Normalizes input AST for UglifyJS in order to get correct comparison.
@@ -62,7 +62,7 @@ module.exports = function(options) {
var ast1 = normalizeInput(esfuzz.generate({
maxDepth: options.maxDepth
}));
var ast2 =
UglifyJS
.AST_Node

View File

@@ -1,15 +1,25 @@
#! /usr/bin/env node
global.UGLIFY_DEBUG = true;
var U = require("../tools/node");
var path = require("path");
var fs = require("fs");
var assert = require("assert");
var vm = require("vm");
var tests_dir = path.dirname(module.filename);
var failures = 0;
var failed_files = {};
var same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
if (typeof expected != typeof actual) return false;
if (typeof expected != "string") {
if (expected.name != actual.name) return false;
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
}
return expected == actual;
} : function(expected, actual) {
return typeof expected == typeof actual && expected.toString() == actual.toString();
};
run_compress_tests();
if (failures) {
@@ -71,10 +81,15 @@ function test_directory(dir) {
}
function as_toplevel(input, mangle_options) {
if (input instanceof U.AST_BlockStatement) input = input.body;
else if (input instanceof U.AST_Statement) input = [ input ];
else throw new Error("Unsupported input syntax");
var toplevel = new U.AST_Toplevel({ body: input });
if (!(input instanceof U.AST_BlockStatement))
throw new Error("Unsupported input syntax");
for (var i = 0; i < input.body.length; i++) {
var stat = input.body[i];
if (stat instanceof U.AST_SimpleStatement && stat.body instanceof U.AST_String)
input.body[i] = new U.AST_Directive(stat.body);
else break;
}
var toplevel = new U.AST_Toplevel(input);
toplevel.figure_out_scope(mangle_options);
return toplevel;
}
@@ -88,6 +103,23 @@ function run_compress_tests() {
function test_case(test) {
log_test(test.name);
U.base54.reset();
var output_options = test.beautify || {};
var expect;
if (test.expect) {
expect = make_code(as_toplevel(test.expect, test.mangle), output_options);
} else {
expect = test.expect_exact;
}
var input = as_toplevel(test.input, test.mangle);
var input_code = make_code(input, output_options);
var input_formatted = make_code(test.input, {
beautify: true,
quote_style: 3,
keep_quoted_props: true
});
if (test.mangle_props) {
input = U.mangle_properties(input, test.mangle_props);
}
var options = U.defaults(test.options, {
warnings: false
});
@@ -97,25 +129,9 @@ function run_compress_tests() {
U.AST_Node.warn_function = function(text) {
warnings_emitted.push("WARN: " + text);
};
options.warnings = true;
if (!options.warnings) options.warnings = true;
}
var cmp = new U.Compressor(options, true);
var output_options = test.beautify || {};
var expect;
if (test.expect) {
expect = make_code(as_toplevel(test.expect, test.mangle), output_options);
} else {
expect = test.expect_exact;
}
var input = as_toplevel(test.input, test.mangle);
var input_code = make_code(test.input, {
beautify: true,
quote_style: 3,
keep_quoted_props: true
});
if (test.mangle_props) {
input = U.mangle_properties(input, test.mangle_props);
}
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);
if (test.mangle) {
@@ -125,7 +141,7 @@ function run_compress_tests() {
output = make_code(output, output_options);
if (expect != output) {
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
input: input_code,
input: input_formatted,
output: output,
expected: expect
});
@@ -138,7 +154,7 @@ function run_compress_tests() {
var reparsed_ast = U.parse(output);
} catch (ex) {
log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", {
input: input_code,
input: input_formatted,
output: output,
error: ex.toString(),
});
@@ -157,7 +173,7 @@ function run_compress_tests() {
var actual_warnings = JSON.stringify(warnings_emitted);
if (expected_warnings != actual_warnings) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
input: input_code,
input: input_formatted,
expected_warnings: expected_warnings,
actual_warnings: actual_warnings,
});
@@ -165,6 +181,36 @@ function run_compress_tests() {
failed_files[file] = 1;
}
}
if (test.expect_stdout) {
var stdout = run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
if (!same_stdout(test.expect_stdout, stdout)) {
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
actual: stdout,
});
failures++;
failed_files[file] = 1;
} else {
stdout = run_code(output);
if (!same_stdout(test.expect_stdout, stdout)) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
actual: stdout,
});
failures++;
failed_files[file] = 1;
}
}
}
}
}
var tests = parse_test(path.resolve(dir, file));
@@ -214,6 +260,23 @@ function parse_test(file) {
}));
}
function read_string(stat) {
if (stat.TYPE == "SimpleStatement") {
var body = stat.body;
switch(body.TYPE) {
case "String":
return body.value;
case "Array":
return body.elements.map(function(element) {
if (element.TYPE !== "String")
throw new Error("Should be array of strings");
return element.value;
}).join("\n");
}
}
throw new Error("Should be string or array of strings");
}
function get_one_test(name, block) {
var test = { name: name, options: {} };
var tw = new U.TreeWalker(function(node, descend){
@@ -226,28 +289,26 @@ function parse_test(file) {
return true;
}
if (node instanceof U.AST_LabeledStatement) {
var label = node.label;
assert.ok(
["input", "expect", "expect_exact", "expect_warnings"].indexOf(node.label.name) >= 0,
["input", "expect", "expect_exact", "expect_warnings", "expect_stdout"].indexOf(label.name) >= 0,
tmpl("Unsupported label {name} [{line},{col}]", {
name: node.label.name,
line: node.label.start.line,
col: node.label.start.col
name: label.name,
line: label.start.line,
col: label.start.col
})
);
var stat = node.body;
if (stat instanceof U.AST_BlockStatement) {
if (stat.body.length == 1) stat = stat.body[0];
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
}
if (node.label.name === "expect_exact") {
if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
throw new Error(
"The value of the expect_exact clause should be a string, " +
"like `expect_exact: \"some.exact.javascript;\"`");
if (label.name == "expect_exact") {
test[label.name] = read_string(stat);
} else if (label.name == "expect_stdout") {
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
test[label.name] = stat.body.value;
} else {
test[label.name] = read_string(stat) + "\n";
}
test[node.label.name] = stat.body.start.value
} else {
test[node.label.name] = stat;
test[label.name] = stat;
}
return true;
}
@@ -269,3 +330,19 @@ function evaluate(code) {
code = make_code(code, { beautify: true });
return new Function("return(" + code + ")")();
}
function run_code(code) {
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
new vm.Script(code).runInNewContext({ console: console }, { timeout: 5000 });
return stdout;
} catch (ex) {
return ex;
} finally {
process.stdout.write = original_write;
}
}

477
test/ufuzz.js Normal file
View File

@@ -0,0 +1,477 @@
// ufuzz.js
// derived from https://github.com/qfox/uglyfuzzer by Peter van der Zee
"use strict";
// workaround for tty output truncation upon process.exit()
[process.stdout, process.stderr].forEach(function(stream){
if (stream._handle && stream._handle.setBlocking)
stream._handle.setBlocking(true);
});
var vm = require("vm");
var minify = require("..").minify;
var MAX_GENERATED_FUNCTIONS_PER_RUN = 1;
var MAX_GENERATION_RECURSION_DEPTH = 15;
var INTERVAL_COUNT = 100;
var VALUES = [
'true',
'false',
'22',
'0',
'-0', // 0/-0 !== 0
'23..toString()',
'24 .toString()',
'25. ',
'0x26.toString()',
'(-1)',
'NaN',
'undefined',
'Infinity',
'null',
'[]',
'[,0][1]', // an array with elisions... but this is always false
'([,0].length === 2)', // an array with elisions... this is always true
'({})', // wrapped the object causes too many syntax errors in statements
'"foo"',
'"bar"' ];
var BINARY_OPS_NO_COMMA = [
' + ', // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
' - ',
'/',
'*',
'&',
'|',
'^',
'<<',
'>>',
'>>>',
'%',
'&&',
'||',
'^' ];
var BINARY_OPS = [','].concat(BINARY_OPS_NO_COMMA);
var ASSIGNMENTS = [
'=',
'=',
'=',
'=',
'=',
'=',
'==',
'!=',
'===',
'!==',
'+=',
'-=',
'*=',
'/=',
'&=',
'|=',
'^=',
'<<=',
'>>=',
'>>>=',
'%=' ];
var UNARY_OPS = [
'--',
'++',
'~',
'!',
'void ',
'delete ', // should be safe, even `delete foo` and `delete f()` shouldn't crash
' - ',
' + ' ];
var NO_COMMA = true;
var MAYBE = true;
var NESTED = true;
var CAN_THROW = true;
var CANNOT_THROW = false;
var CAN_BREAK = true;
var CAN_CONTINUE = true;
var VAR_NAMES = [
'foo',
'bar',
'a',
'b',
'undefined', // fun!
'eval', // mmmm, ok, also fun!
'NaN', // mmmm, ok, also fun!
'Infinity', // the fun never ends!
'arguments', // this one is just creepy
'Math', // since Math is assumed to be a non-constructor/function it may trip certain cases
'let' ]; // maybe omit this, it's more a parser problem than minifier
var TYPEOF_OUTCOMES = [
'undefined',
'string',
'number',
'object',
'boolean',
'special',
'unknown',
'symbol',
'crap' ];
var FUNC_TOSTRING = [
"Function.prototype.toString = function() {",
" var ids = [];",
" return function() {",
" var i = ids.indexOf(this);",
" if (i < 0) {",
" i = ids.length;",
" ids.push(this);",
" }",
' return "[Function: __func_" + i + "__]";',
" }",
"}();",
""
].join("\n");
function run_code(code) {
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
new vm.Script(FUNC_TOSTRING + code).runInNewContext({
console: {
log: function() {
return console.log.apply(console, [].map.call(arguments, function(arg) {
return typeof arg == "function" ? "[Function]" : arg;
}));
}
}
}, { timeout: 5000 });
return stdout;
} catch (ex) {
return ex;
} finally {
process.stdout.write = original_write;
}
}
function rng(max) {
return Math.floor(max * Math.random());
}
function createFunctionDecls(n, recurmax, nested) {
if (--recurmax < 0) { return ';'; }
var s = '';
while (n-- > 0) {
s += createFunctionDecl(recurmax, nested) + '\n';
}
return s;
}
var funcs = 0;
function createFunctionDecl(recurmax, nested) {
if (--recurmax < 0) { return ';'; }
var func = funcs++;
var name = rng(5) > 0 ? 'f' + func : createVarName();
if (name === 'a' || name === 'b') name = 'f' + func; // quick hack to prevent assignment to func names of being called
if (!nested && name === 'undefined' || name === 'NaN' || name === 'Infinity') name = 'f' + func; // cant redefine these in global space
var s = '';
if (rng(5) === 1) {
// functions with functions. lower the recursion to prevent a mess.
s = 'function ' + name + '(){' + createFunctionDecls(rng(5) + 1, Math.ceil(recurmax / 2), NESTED) + '}\n';
} else {
// functions with statements
s = 'function ' + name + '(){' + createStatements(3, recurmax) + '}\n';
}
if (nested) s = '!' + nested; // avoid "function statements" (decl inside statements)
else s += name + '();'
return s;
}
function createStatements(n, recurmax, canThrow, canBreak, canContinue) {
if (--recurmax < 0) { return ';'; }
var s = '';
while (--n > 0) {
s += createStatement(recurmax, canThrow, canBreak, canContinue);
}
return s;
}
var loops = 0;
function createStatement(recurmax, canThrow, canBreak, canContinue) {
var loop = ++loops;
if (--recurmax < 0) { return ';'; }
switch (rng(16)) {
case 0:
return '{' + createStatements(rng(5) + 1, recurmax, canThrow, canBreak, canContinue) + '}';
case 1:
return 'if (' + createExpression(recurmax) + ')' + createStatement(recurmax, canThrow, canBreak, canContinue) + (rng(2) === 1 ? ' else ' + createStatement(recurmax, canThrow, canBreak, canContinue) : '');
case 2:
return '{var brake' + loop + ' = 5; do {' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE) + '} while ((' + createExpression(recurmax) + ') && --brake' + loop + ' > 0);}';
case 3:
return '{var brake' + loop + ' = 5; while ((' + createExpression(recurmax) + ') && --brake' + loop + ' > 0)' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE) + '}';
case 4:
return 'for (var brake' + loop + ' = 5; (' + createExpression(recurmax) + ') && brake' + loop + ' > 0; --brake' + loop + ')' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE);
case 5:
return ';';
case 6:
return createExpression(recurmax) + ';';
case 7:
// note: case args are actual expressions
// note: default does not _need_ to be last
return 'switch (' + createExpression(recurmax) + ') { ' + createSwitchParts(recurmax, 4) + '}';
case 8:
return 'var ' + createVarName() + ';';
case 9:
// initializer can only have one expression
return 'var ' + createVarName() + ' = ' + createExpression(recurmax, NO_COMMA) + ';';
case 10:
// initializer can only have one expression
return 'var ' + createVarName() + ' = ' + createExpression(recurmax, NO_COMMA) + ', ' + createVarName() + ' = ' + createExpression(recurmax, NO_COMMA) + ';';
case 11:
if (canBreak && rng(5) === 0) return 'break;';
if (canContinue && rng(5) === 0) return 'continue;';
return 'return;';
case 12:
// must wrap in curlies to prevent orphaned `else` statement
if (canThrow && rng(5) === 0) return '{ throw ' + createExpression(recurmax) + '}';
return '{ return ' + createExpression(recurmax) + '}';
case 13:
// this is actually more like a parser test, but perhaps it hits some dead code elimination traps
// must wrap in curlies to prevent orphaned `else` statement
if (canThrow && rng(5) === 0) return '{ throw\n' + createExpression(recurmax) + '}';
return '{ return\n' + createExpression(recurmax) + '}';
case 14:
// "In non-strict mode code, functions can only be declared at top level, inside a block, or ..."
// (dont both with func decls in `if`; it's only a parser thing because you cant call them without a block)
return '{' + createFunctionDecl(recurmax, NESTED) + '}';
case 15:
return ';';
// catch var could cause some problems
// note: the "blocks" are syntactically mandatory for try/catch/finally
var s = 'try {' + createStatement(recurmax, CAN_THROW, canBreak, canContinue) + ' }';
var n = rng(3); // 0=only catch, 1=only finally, 2=catch+finally
if (n !== 1) s += ' catch (' + createVarName() + ') { ' + createStatements(3, recurmax, canBreak, canContinue) + ' }';
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canBreak, canContinue) + ' }';
return s;
}
}
function createSwitchParts(recurmax, n) {
var hadDefault = false;
var s = '';
while (n-- > 0) {
hadDefault = n > 0;
if (hadDefault || rng(4) > 0) {
s += '' +
'case ' + createExpression(recurmax) + ':\n' +
createStatements(rng(3) + 1, recurmax, CANNOT_THROW, CAN_BREAK) +
'\n' +
(rng(10) > 0 ? ' break;' : '/* fall-through */') +
'\n';
} else {
hadDefault = true;
s += '' +
'default:\n' +
createStatements(rng(3) + 1, recurmax, CANNOT_THROW, CAN_BREAK) +
'\n';
}
}
return s;
}
function createExpression(recurmax, noComma) {
if (--recurmax < 0) {
return createValue(); // note: should return a simple non-recursing expression value!
}
switch (rng(12)) {
case 0:
return '(' + createUnaryOp() + (rng(2) === 1 ? 'a' : 'b') + ')';
case 1:
return '(a' + (rng(2) == 1 ? '++' : '--') + ')';
case 2:
return '(b ' + createAssignment() + ' a)';
case 3:
return '(' + rng(2) + ' === 1 ? a : b)';
case 4:
return createExpression(recurmax, noComma) + createBinaryOp(noComma) + createExpression(recurmax, noComma);
case 5:
return createValue();
case 6:
return '(' + createExpression(recurmax) + ')';
case 7:
return createExpression(recurmax, noComma) + '?(' + createExpression(recurmax) + '):(' + createExpression(recurmax) + ')';
case 8:
switch(rng(4)) {
case 0:
return '(function ' + createVarName(MAYBE) + '(){' + createStatements(rng(5) + 1, recurmax) + '})()';
case 1:
return '+function ' + createVarName(MAYBE) + '(){' + createStatements(rng(5) + 1, recurmax) + '}';
case 2:
return '!function ' + createVarName(MAYBE) + '(){' + createStatements(rng(5) + 1, recurmax) + '}';
case 3:
return 'void function ' + createVarName(MAYBE) + '(){' + createStatements(rng(5) + 1, recurmax) + '}';
default:
return 'void function ' + createVarName(MAYBE) + '(){' + createStatements(rng(5) + 1, recurmax) + '}';
}
case 9:
return createTypeofExpr(recurmax);
case 10:
// you could statically infer that this is just `Math`, regardless of the other expression
// I don't think Uglify does this at this time...
return ''+
'new function(){ \n' +
(rng(2) === 1 ? createExpression(recurmax) + '\n' : '') +
'return Math;\n' +
'}';
case 11:
// more like a parser test but perhaps comment nodes mess up the analysis?
switch (rng(5)) {
case 0:
return '(a/* ignore */++)';
case 1:
return '(b/* ignore */--)';
case 2:
return '(++/* ignore */a)';
case 3:
return '(--/* ignore */b)';
case 4:
// only groups that wrap a single variable return a "Reference", so this is still valid.
// may just be a parser edge case that is invisible to uglify...
return '(--(b))';
default:
return '(--/* ignore */b)';
}
}
}
function createTypeofExpr(recurmax) {
if (--recurmax < 0) {
return 'typeof undefined === "undefined"';
}
switch (rng(5)) {
case 0:
return '(typeof ' + createVarName() + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
case 1:
return '(typeof ' + createVarName() + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
case 2:
return '(typeof ' + createVarName() + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
case 3:
return '(typeof ' + createVarName() + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '")';
case 4:
return '(typeof ' + createVarName() + ')';
}
}
function createValue() {
return VALUES[rng(VALUES.length)];
}
function createBinaryOp(noComma) {
if (noComma) return BINARY_OPS_NO_COMMA[rng(BINARY_OPS_NO_COMMA.length)];
return BINARY_OPS[rng(BINARY_OPS.length)];
}
function createAssignment() {
return ASSIGNMENTS[rng(ASSIGNMENTS.length)];
}
function createUnaryOp() {
return UNARY_OPS[rng(UNARY_OPS.length)];
}
function createVarName(maybe) {
if (!maybe || rng(2) === 1) {
return VAR_NAMES[rng(VAR_NAMES.length)] + (rng(5) > 0 ? ++loops : '');
}
return '';
}
function log(ok) {
console.log("//=============================================================");
if (!ok) console.log("// !!!!!! Failed...");
console.log("// original code");
console.log("//");
console.log(original_code);
console.log();
console.log();
console.log("//-------------------------------------------------------------");
console.log("// original code (beautify'd)");
console.log("//");
console.log(beautify_code);
console.log();
console.log();
console.log("//-------------------------------------------------------------");
console.log("// uglified code");
console.log("//");
console.log(uglify_code);
console.log();
console.log();
console.log("original result:");
console.log(original_result);
console.log("beautified result:");
console.log(beautify_result);
console.log("uglified result:");
console.log(uglify_result);
if (!ok) console.log("!!!!!! Failed...");
}
var num_iterations = +process.argv[2] || 1/0;
var verbose = process.argv[3] === 'v' || process.argv[2] === 'v';
var verbose_interval = process.argv[3] === 'V' || process.argv[2] === 'V';
for (var round = 0; round < num_iterations; round++) {
var parse_error = false;
process.stdout.write(round + " of " + num_iterations + "\r");
var original_code = [
"var a = 100, b = 10;",
createFunctionDecls(rng(MAX_GENERATED_FUNCTIONS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH),
"console.log(a, b);"
].join("\n");
var original_result = run_code(original_code);
try {
var beautify_code = minify(original_code, {
fromString: true,
mangle: false,
compress: false,
output: {
beautify: true,
bracketize: true,
},
}).code;
} catch(e) {
parse_error = 1;
}
var beautify_result = run_code(beautify_code);
try {
var uglify_code = minify(beautify_code, {
fromString: true,
mangle: true,
compress: {
passes: 3,
},
output: {
//beautify: true,
//bracketize: true,
},
}).code;
} catch(e) {
parse_error = 2;
}
var uglify_result = run_code(uglify_code);
var ok = !parse_error && original_result == beautify_result && original_result == uglify_result;
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(ok);
if (parse_error === 1) console.log('Parse error while beautifying');
if (parse_error === 2) console.log('Parse error while uglifying');
if (!ok) break;
}

View File

@@ -17,7 +17,3 @@ exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier;
exports["SymbolDef"] = SymbolDef;
if (typeof DEBUG !== "undefined" && DEBUG) {
exports["EXPECT_DIRECTIVE"] = EXPECT_DIRECTIVE;
}

View File

@@ -7,7 +7,8 @@
var path = require("path");
var fs = require("fs");
var FILES = exports.FILES = [
var UglifyJS = exports;
var FILES = UglifyJS.FILES = [
"../lib/utils.js",
"../lib/ast.js",
"../lib/parse.js",
@@ -20,17 +21,14 @@ var FILES = exports.FILES = [
"../lib/propmangle.js",
"./exports.js",
].map(function(file){
return fs.realpathSync(path.join(path.dirname(__filename), file));
return require.resolve(file);
});
var UglifyJS = exports;
new Function("MOZ_SourceMap", "exports", "DEBUG", FILES.map(function(file){
new Function("MOZ_SourceMap", "exports", FILES.map(function(file){
return fs.readFileSync(file, "utf8");
}).join("\n\n"))(
require("source-map"),
UglifyJS,
!!global.UGLIFY_DEBUG
UglifyJS
);
UglifyJS.AST_Node.warn_function = function(txt) {
@@ -46,7 +44,7 @@ function read_source_map(code) {
return JSON.parse(new Buffer(match[2], "base64"));
}
exports.minify = function(files, options) {
UglifyJS.minify = function(files, options) {
options = UglifyJS.defaults(options, {
spidermonkey : false,
outSourceMap : null,
@@ -181,7 +179,7 @@ exports.minify = function(files, options) {
};
};
// exports.describe_ast = function() {
// UglifyJS.describe_ast = function() {
// function doitem(ctor) {
// var sub = {};
// ctor.SUBCLASSES.forEach(function(ctor){
@@ -195,7 +193,7 @@ exports.minify = function(files, options) {
// return doitem(UglifyJS.AST_Node).sub;
// }
exports.describe_ast = function() {
UglifyJS.describe_ast = function() {
var out = UglifyJS.OutputStream({ beautify: true });
function doitem(ctor) {
out.print("AST_" + ctor.TYPE);
@@ -249,13 +247,13 @@ function readReservedFile(filename, reserved) {
return reserved;
}
exports.readReservedFile = readReservedFile;
UglifyJS.readReservedFile = readReservedFile;
exports.readDefaultReservedFile = function(reserved) {
return readReservedFile(path.join(__dirname, "domprops.json"), reserved);
UglifyJS.readDefaultReservedFile = function(reserved) {
return readReservedFile(require.resolve("./domprops.json"), reserved);
};
exports.readNameCache = function(filename, key) {
UglifyJS.readNameCache = function(filename, key) {
var cache = null;
if (filename) {
try {
@@ -273,7 +271,7 @@ exports.readNameCache = function(filename, key) {
return cache;
};
exports.writeNameCache = function(filename, key, cache) {
UglifyJS.writeNameCache = function(filename, key, cache) {
if (filename) {
var data;
try {
@@ -294,13 +292,9 @@ exports.writeNameCache = function(filename, key, cache) {
// Example: "foo/bar/*baz??.*.js"
// Argument `glob` may be a string or an array of strings.
// Returns an array of strings. Garbage in, garbage out.
exports.simple_glob = function simple_glob(glob) {
var results = [];
UglifyJS.simple_glob = function simple_glob(glob) {
if (Array.isArray(glob)) {
glob.forEach(function(elem) {
results = results.concat(simple_glob(elem));
});
return results;
return [].concat.apply([], glob.map(simple_glob));
}
if (glob.match(/\*|\?/)) {
var dir = path.dirname(glob);
@@ -308,28 +302,19 @@ exports.simple_glob = function simple_glob(glob) {
var entries = fs.readdirSync(dir);
} catch (ex) {}
if (entries) {
var pattern = "^" + (path.basename(glob)
.replace(/\(/g, "\\(")
.replace(/\)/g, "\\)")
.replace(/\{/g, "\\{")
.replace(/\}/g, "\\}")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]")
.replace(/\+/g, "\\+")
.replace(/\^/g, "\\^")
.replace(/\$/g, "\\$")
var pattern = "^" + path.basename(glob)
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
.replace(/\*/g, "[^/\\\\]*")
.replace(/\./g, "\\.")
.replace(/\?/g, ".")) + "$";
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
for (var i in entries) {
if (rx.test(entries[i]))
results.push(dir + "/" + entries[i]);
}
var results = entries.filter(function(name) {
return rx.test(name);
}).map(function(name) {
return path.join(dir, name);
});
if (results.length) return results;
}
}
if (results.length === 0)
results = [ glob ];
return results;
return [ glob ];
};