diff --git a/go.mod b/go.mod index 99c48a5ef8..33449f4ca0 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/tdewolff/minify/v2 go 1.13 +replace github.com/tdewolff/parse/v2 => ../parse + require ( github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect github.com/dustin/go-humanize v1.0.0 diff --git a/js/js.go b/js/js.go index 03ce83e365..3a1dcaf13f 100644 --- a/js/js.go +++ b/js/js.go @@ -388,6 +388,9 @@ func (m *jsMinifier) minifyStmt(i js.IStmt) { } m.requireSemicolon() } + case *js.DirectivePrologueStmt: + m.write(stmt.Value) + m.requireSemicolon() } } diff --git a/js/js_test.go b/js/js_test.go index 0c77265f7f..ec641771d8 100644 --- a/js/js_test.go +++ b/js/js_test.go @@ -126,29 +126,29 @@ func TestJS(t *testing.T) { {`try {a} finally {c}`, `try{a}finally{c}`}, {`a=b;c=d`, `a=b,c=d`}, - // strings - {`""`, `""`}, - {`"\x7"`, `"\x7"`}, - {`"string\'string"`, `"string'string"`}, - {`'string\"string'`, `'string"string'`}, - {`'string\t\f\v\bstring'`, "'string\t\f\v\bstring'"}, - {`"string\a\c\'string"`, `"stringac'string"`}, - {`"string\∀string"`, `"string∀string"`}, - {`"string\0\uFFFFstring"`, `"string\0\uFFFFstring"`}, - {`"string\x00\x55\x0A\x0D\x22\x27string"`, `"string\0U\n\r\"'string"`}, - {`"string\000\12\015\042\47\411string"`, `"string\0\n\r\"'!1string"`}, - {"'string\\n\\rstring'", "'string\\n\\rstring'"}, - {"'string\\\r\nstring\\\nstring\\\rstring\\\u2028string\\\u2029string'", "'stringstringstringstringstringstring'"}, - {`"str1ng" + "str2ng"`, `"str1ngstr2ng"`}, - {`"str1ng" + "str2ng" + "str3ng"`, `"str1ngstr2ngstr3ng"`}, - {`"padding" + this`, `"padding"+this`}, - {`"<\/script>"`, `"<\/script>"`}, - {`""`, `"<\/script>"`}, - {`"\""`, `'"'`}, - {`'\'""'`, `'\'""'`}, - {`"\"\"a'"`, `'""a\''`}, - {`"'" + '"'`, `"'\""`}, - {`'"' + "'"`, `'"\''`}, + // strings (prepend '0,' to avoid being a directive prologue) + {`0,""`, `0,""`}, + {`0,"\x7"`, `0,"\x7"`}, + {`0,"string\'string"`, `0,"string'string"`}, + {`0,'string\"string'`, `0,'string"string'`}, + {`0,'string\t\f\v\bstring'`, "0,'string\t\f\v\bstring'"}, + {`0,"string\a\c\'string"`, `0,"stringac'string"`}, + {`0,"string\∀string"`, `0,"string∀string"`}, + {`0,"string\0\uFFFFstring"`, `0,"string\0\uFFFFstring"`}, + {`0,"string\x00\x55\x0A\x0D\x22\x27string"`, `0,"string\0U\n\r\"'string"`}, + {`0,"string\000\12\015\042\47\411string"`, `0,"string\0\n\r\"'!1string"`}, + {"0,'string\\n\\rstring'", "0,'string\\n\\rstring'"}, + {"0,'string\\\r\nstring\\\nstring\\\rstring\\\u2028string\\\u2029string'", "0,'stringstringstringstringstringstring'"}, + {`0,"str1ng" + "str2ng"`, `0,"str1ngstr2ng"`}, + {`0,"str1ng" + "str2ng" + "str3ng"`, `0,"str1ngstr2ngstr3ng"`}, + {`0,"padding" + this`, `0,"padding"+this`}, + {`0,"<\/script>"`, `0,"<\/script>"`}, + {`0,""`, `0,"<\/script>"`}, + {`0,"\""`, `0,'"'`}, + {`0,'\'""'`, `0,'\'""'`}, + {`0,"\"\"a'"`, `0,'""a\''`}, + {`0,"'" + '"'`, `0,"'\""`}, + {`0,'"' + "'"`, `0,'"\''`}, // rename true, false, undefined, Infinity {`x=true`, `x=!0`}, @@ -312,6 +312,7 @@ func TestJS(t *testing.T) { {`var a;var {}=b;`, `var a;{}=b`}, {`"use strict";var a;var b;b=5`, `"use strict";var b=5,a`}, {`"use strict";z+=6;var a;var b;b=5`, `"use strict";var a,b;z+=6,b=5`}, + {`!function(){"use strict";return a}`, `!function(){"use strict";return a}`}, // function and method declarations {`function g(){return}`, `function g(){}`}, diff --git a/js/vars.go b/js/vars.go index efa4164ce1..24db40bb6e 100644 --- a/js/vars.go +++ b/js/vars.go @@ -200,9 +200,11 @@ func (m *jsMinifier) hoistVars(body *js.BlockStmt) *js.VarDecl { // ignore "use strict" declStart := 0 - if expr, ok := body.List[0].(*js.ExprStmt); ok { - if lit, ok := expr.Value.(*js.LiteralExpr); ok && lit.TokenType == js.StringToken && bytes.Equal(lit.Data, useStrictBytes) { - declStart = 1 + for { + if _, ok := body.List[declStart].(*js.DirectivePrologueStmt); ok { + declStart++ + } else { + break } }