diff --git a/lib/ast.js b/lib/ast.js index 598833f3..6ef203dc 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -448,10 +448,8 @@ var AST_TemplateString = DEFNODE("TemplateString", "segments", { }, _walk: function(visitor) { return visitor._visit(this, function(){ - this.segments.forEach(function(seg, i){ - if (i % 2 !== 0) { - seg._walk(visitor); - } + this.segments.forEach(function(seg){ + seg._walk(visitor); }); }); } diff --git a/lib/compress.js b/lib/compress.js index 55153f5e..8df9f4b2 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2230,6 +2230,10 @@ merge(Compressor.prototype, { return expression.has_side_effects(compressor); }); }); + def(AST_TemplateSegment, return_false); + def(AST_TemplateString, function(compressor){ + return any(this.segments, compressor); + }); })(function(node, func){ node.DEFMETHOD("has_side_effects", func); }); @@ -2944,6 +2948,11 @@ merge(Compressor.prototype, { def(AST_Expansion, function(compressor, first_in_statement){ return this.expression.drop_side_effect_free(compressor, first_in_statement); }); + def(AST_TemplateSegment, return_null); + def(AST_TemplateString, function(compressor){ + var values = trim(this.segments, compressor, first_in_statement); + return values && make_sequence(this, values); + }); })(function(node, func){ node.DEFMETHOD("drop_side_effect_free", func); }); @@ -4888,7 +4897,7 @@ merge(Compressor.prototype, { } self.segments = segments; - return self; + return segments.length == 1 ? make_node(AST_String, self, segments[0]) : self; }); OPT(AST_PrefixedTemplateString, function(self, compressor){ diff --git a/lib/output.js b/lib/output.js index 74771b1f..9082fbcd 100644 --- a/lib/output.js +++ b/lib/output.js @@ -262,7 +262,7 @@ function OutputStream(options) { } } : noop; - var requireSemicolonChars = makePredicate("( [ + * / - , ."); + var requireSemicolonChars = makePredicate("( [ + * / - , . `"); function print(str) { str = String(str); diff --git a/lib/transform.js b/lib/transform.js index 014a82e4..a5a93026 100644 --- a/lib/transform.js +++ b/lib/transform.js @@ -262,11 +262,7 @@ TreeTransformer.prototype = new TreeWalker; }); _(AST_TemplateString, function(self, tw) { - for (var i = 0; i < self.segments.length; i++) { - if (!(self.segments[i] instanceof AST_TemplateSegment)) { - self.segments[i] = self.segments[i].transform(tw); - } - } + self.segments = do_list(self.segments, tw); }); _(AST_PrefixedTemplateString, function(self, tw) { diff --git a/test/compress/template-string.js b/test/compress/template-string.js index d9570c0a..5e6e01f8 100644 --- a/test/compress/template-string.js +++ b/test/compress/template-string.js @@ -59,7 +59,7 @@ template_string_with_constant_expression: { var foo = `${4 + 4} equals 4 + 4`; } expect: { - var foo = `8 equals 4 + 4`; + var foo = "8 equals 4 + 4"; } } @@ -89,21 +89,21 @@ template_string_with_predefined_constants: { var c = `${4**14}`; // 8 in template vs 9 chars - 268435456 } expect: { - var foo = `This is undefined`; - var bar = `This is NaN`; - var baz = `This is null`; + var foo = "This is undefined"; + var bar = "This is NaN"; + var baz = "This is null"; var foofoo = `This is ${1/0}`; var foobar = "This is ${1/0}"; var foobaz = 'This is ${1/0}'; var barfoo = "This is ${NaN}"; var bazfoo = "This is ${null}"; var bazbaz = `This is ${1/0}`; - var barbar = `This is NaN`; + var barbar = "This is NaN"; var barbar = "This is ${0/0}"; var barber = 'This is ${0/0}'; - var a = `4194304`; - var b = `16777216`; // Potential for further concatentation + var a = "4194304"; + var b = "16777216"; // Potential for further concatentation var c = `${4**14}`; // Not worth converting } } @@ -123,7 +123,7 @@ template_string_evaluate_with_many_segments: { } expect: { var foo = `Hello ${guest()}, welcome to ${location()}.`; - var bar = `1234567890`; + var bar = "1234567890"; var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`; var buzz = `1${foobar()}2${foobar()}3${foobar()}`; } @@ -159,7 +159,7 @@ template_string_to_normal_string: { var bar = "Decimals " + `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`; } expect: { - var foo = `This is undefined`; + var foo = "This is undefined"; var bar = "Decimals 1234567890"; } } @@ -192,7 +192,7 @@ evaluate_nested_templates: { var baz = `${`${`${`foo`}`}`}`; } expect: { - var baz = `foo`; + var baz = "foo"; } } @@ -241,8 +241,8 @@ enforce_double_quotes_and_evaluate: { var baz = `Hello ${world()}`; } expect: { - var foo = `Hello world`; - var bar = `Hello world`; + var foo = "Hello world"; + var bar = "Hello world"; var baz = `Hello ${world()}`; } } @@ -260,8 +260,8 @@ enforce_single_quotes_and_evaluate: { var baz = `Hello ${world()}`; } expect: { - var foo = `Hello world`; - var bar = `Hello world`; + var foo = "Hello world"; + var bar = "Hello world"; var baz = `Hello ${world()}`; } } @@ -339,7 +339,7 @@ escape_dollar_curly: { console.log(`${1-0}\${2-0}$\{3-0}${4-0}`) console.log(`$${""}{not an expression}`) } - expect_exact: "console.log(`\\${ beep }`);console.log(`1\\${2-0}\\${3-0}4`);console.log(`\\${not an expression}`);" + expect_exact: 'console.log("${ beep }");console.log("1${2-0}${3-0}4");console.log("${not an expression}");' } template_starting_with_newline: { @@ -400,3 +400,61 @@ issue_1856_ascii_only: { } expect_exact: "console.log(`\\\\n\\\\r\\\\u2028\\\\u2029\\n\\r\\u2028\\u2029`);" } + +side_effects: { + options = { + evaluate: true, + side_effects: true, + } + input: { + `t1`; + tag`t2`; + `t${3}`; + tag`t${4}`; + console.log(` +t${5}`); + function f(a) { + `t6${a}`; + a = `t7${a}` & a; + a = `t8${b}` | a; + a = f`t9${a}` ^ a; + } + } + expect: { + tag`t2`; + tag`t${4}`; + console.log("\nt5"); + function f(a) { + a &= `t7${a}`; + a = `t8${b}` | a; + a = f`t9${a}` ^ a; + } + } +} + +simple_string: { + options = { + computed_props: true, + evaluate: true, + properties: true, + } + input: { + console.log({[`foo`]: 1}[`foo`], `hi` == "hi", `world`); + } + expect: { + console.log({foo: 1}.foo, true, "world"); + } + expect_stdout: "1 true 'world'" + node_version: ">=4" +} + +semicolons: { + beautify = { + semicolons: false, + } + input: { + foo; + `bar`; + } + expect_exact: "foo;`bar`\n" +}