aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--lib/compress.js40
-rw-r--r--lib/output.js19
-rw-r--r--test/compress/negate-iife.js76
4 files changed, 126 insertions, 16 deletions
diff --git a/README.md b/README.md
index b735eb6e..ad394b25 100644
--- a/README.md
+++ b/README.md
@@ -209,6 +209,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
and `x = something(), x` into `x = something()`
- `warnings` -- display warnings when dropping unreachable code or unused
declarations etc.
+- `negate_iife` -- negate "Immediately-Called Function Expressions"
+ where the return value is discarded, to avoid the parens that the
+ code generator would insert.
### The `unsafe` option
@@ -296,10 +299,6 @@ can pass additional arguments that control the code output:
you pass `false` then whenever possible we will use a newline instead of a
semicolon, leading to more readable output of uglified code (size before
gzip could be smaller; size after gzip insignificantly larger).
-- `negate-iife` (default `!beautify`) -- prefer negation, rather than
- parens, for "Immediately-Called Function Expressions". This defaults to
- `true` when beautification is off, and `false` if beautification is on;
- pass it manually to force a value.
### Keeping copyright notices or other comments
diff --git a/lib/compress.js b/lib/compress.js
index 8dfbc72b..8d936bac 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -66,6 +66,7 @@ function Compressor(options, false_by_default) {
join_vars : !false_by_default,
cascade : !false_by_default,
side_effects : !false_by_default,
+ negate_iife : !false_by_default,
screw_ie8 : false,
warnings : true,
@@ -214,6 +215,11 @@ merge(Compressor.prototype, {
statements = join_consecutive_vars(statements, compressor);
}
} while (CHANGED);
+
+ if (compressor.option("negate_iife")) {
+ negate_iifes(statements, compressor);
+ }
+
return statements;
function eliminate_spurious_blocks(statements) {
@@ -497,6 +503,40 @@ merge(Compressor.prototype, {
}, []);
};
+ function negate_iifes(statements, compressor) {
+ statements.forEach(function(stat){
+ if (stat instanceof AST_SimpleStatement) {
+ stat.body = (function transform(thing) {
+ return thing.transform(new TreeTransformer(function(node){
+ if (node instanceof AST_Call && node.expression instanceof AST_Function) {
+ return make_node(AST_UnaryPrefix, node, {
+ operator: "!",
+ expression: node
+ });
+ }
+ else if (node instanceof AST_Call) {
+ node.expression = transform(node.expression);
+ }
+ else if (node instanceof AST_Seq) {
+ node.car = transform(node.car);
+ }
+ else if (node instanceof AST_Conditional) {
+ var expr = transform(node.condition);
+ if (expr !== node.condition) {
+ // it has been negated, reverse
+ node.condition = expr;
+ var tmp = node.consequent;
+ node.consequent = node.alternative;
+ node.alternative = tmp;
+ }
+ }
+ return node;
+ }));
+ })(stat.body);
+ }
+ });
+ };
+
};
function extract_declarations_from_unreachable_code(compressor, stat, target) {
diff --git a/lib/output.js b/lib/output.js
index 6d0dac5a..b7bcd1e3 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -61,7 +61,6 @@ function OutputStream(options) {
comments : false,
preserve_line : false,
screw_ie8 : false,
- negate_iife : !(options && options.beautify),
}, true);
var indentation = 0;
@@ -351,21 +350,17 @@ function OutputStream(options) {
AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen;
- stream.push_node(self);
- var needs_parens = self.needs_parens(stream);
- var fc = self instanceof AST_Function && stream.option("negate_iife");
- if (force_parens || (needs_parens && !fc)) {
- stream.with_parens(function(){
- self.add_comments(stream);
- self.add_source_map(stream);
- generator(self, stream);
- });
- } else {
+ function doit() {
self.add_comments(stream);
- if (needs_parens && fc) stream.print("!");
self.add_source_map(stream);
generator(self, stream);
}
+ stream.push_node(self);
+ if (force_parens || self.needs_parens(stream)) {
+ stream.with_parens(doit);
+ } else {
+ doit();
+ }
stream.pop_node();
});
diff --git a/test/compress/negate-iife.js b/test/compress/negate-iife.js
new file mode 100644
index 00000000..0362ffce
--- /dev/null
+++ b/test/compress/negate-iife.js
@@ -0,0 +1,76 @@
+negate_iife_1: {
+ options = {
+ negate_iife: true
+ };
+ input: {
+ (function(){ stuff() })();
+ }
+ expect: {
+ !function(){ stuff() }();
+ }
+}
+
+negate_iife_2: {
+ options = {
+ negate_iife: true
+ };
+ input: {
+ (function(){ return {} })().x = 10; // should not transform this one
+ }
+ expect: {
+ (function(){ return {} })().x = 10;
+ }
+}
+
+negate_iife_3: {
+ options = {
+ negate_iife: true,
+ };
+ input: {
+ (function(){ return true })() ? console.log(true) : console.log(false);
+ }
+ expect: {
+ !function(){ return true }() ? console.log(false) : console.log(true);
+ }
+}
+
+negate_iife_3: {
+ options = {
+ negate_iife: true,
+ sequences: true
+ };
+ input: {
+ (function(){ return true })() ? console.log(true) : console.log(false);
+ (function(){
+ console.log("something");
+ })();
+ }
+ expect: {
+ !function(){ return true }() ? console.log(false) : console.log(true), function(){
+ console.log("something");
+ }();
+ }
+}
+
+negate_iife_4: {
+ options = {
+ negate_iife: true,
+ sequences: true,
+ conditionals: true,
+ };
+ input: {
+ if ((function(){ return true })()) {
+ console.log(true);
+ } else {
+ console.log(false);
+ }
+ (function(){
+ console.log("something");
+ })();
+ }
+ expect: {
+ !function(){ return true }() ? console.log(false) : console.log(true), function(){
+ console.log("something");
+ }();
+ }
+}