Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions js/js_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ func TestJS(t *testing.T) {
{`var a;var b=6;a=7`, `var b=6,a=7`}, // swap declaration order to maintain definition order
{`var a=5;var b=6;a=7`, `var a=5,b=6;a=7`},
{`var a;var b=6;z=7`, `var b=6,a;z=7`},
//{`for(var a=6,b=7;;);var c=8`, `for(var a=6,b=7,c=8;;);`},
//{`while(b);var a=4;var b=5;`, `for(var a=4,b=5;b;);`},
//{`for(var c;b;){let a=8};var a`, `for(var c,a;b;)let a=8`},
{`for(var a=6,b=7;;);var c=8`, `for(var a=6,b=7,c=8;;);`},
{`for(var c;b;){let a=8};var a`, `for(var c,a;b;)let a=8`},
{`for(;b;){let a=8};var a;var b`, `for(var a,b;b;)let a=8`},

// function and method declarations
{`function g(){return}`, `function g(){}`},
Expand Down Expand Up @@ -536,7 +536,11 @@ func TestJS(t *testing.T) {
{`a={b(c){d}}`, `a={b(c){d}}`},
{`a(b,...c)`, `a(b,...c)`},
//{`'a b c'.split(' ')`, `['a','b','c']`}, // TODO?
//{`!function(){var a}`, `!function(){}`}, // TODO? remove unused variables
//{`!function(){var a}`, `!function(){}`}, // TODO: remove unused variables
//{`const a=6;f(a)`, `f(6)`}, // TODO: inline single-use variables that are literals
//{`let a="string";f(a)`, `f("string")`}, // TODO: inline single-use variables that are literals
{`let a="string"`, `let a="string"`},
//{`{let a="string"}`, ``}, // TODO: remove unused variables that are not in global scope

// merge expressions
{`b=5;return a+b`, `return b=5,a+b`},
Expand All @@ -551,8 +555,11 @@ func TestJS(t *testing.T) {
{`a in 5;for(;b;)c()`, `for((a in 5);b;)c()`}, // is longer
{`a in 5;for(b=4;b;)c()`, `a in 5;for(b=4;b;)c()`},
{`var a=5;for(;b;)c()`, `for(var a=5;b;)c()`},
{`let a=5;for(;b;)c()`, `let a=5;for(;b;)c()`},
{`var a=b in c;for(;b;)c()`, `for(var a=(b in c);b;)c()`},
{`var a=5;while(b)c()`, `for(var a=5;b;)c()`},
{`let a=5;while(b)c()`, `let a=5;while(b)c()`},
//{`var a;for(a=5;b;)c()`, `for(var a=5;b;)c()`}, // TODO
{`a=5;for(var b=4;b;)c()`, `a=5;for(var b=4;b;)c()`},
{`a=5;switch(b=4){}`, `switch(a=5,b=4){}`},
{`a=5;with(b=4){}`, `with(a=5,b=4);`},
Expand Down
16 changes: 10 additions & 6 deletions js/stmtlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,19 @@ func (m *jsMinifier) optimizeStmtList(list []js.IStmt, blockType blockType) []js
j--
}
} else if left, ok := list[i-1].(*js.VarDecl); ok {
if right, ok := list[i].(*js.VarDecl); ok && left.TokenType != js.VarToken && left.TokenType == right.TokenType {
// merge const, let declarations
if right, ok := list[i].(*js.VarDecl); ok && left.TokenType == right.TokenType {
// merge const and let declarations
right.List = append(left.List, right.List...)
j--
} else if forStmt, ok := list[i].(*js.ForStmt); ok && forStmt.Init == nil {
} else if forStmt, ok := list[i].(*js.ForStmt); ok && left.TokenType == js.VarToken {
// TODO: only merge statements that don't have 'in' or 'of' keywords (slow to check?)
forStmt.Init = left
j--
} else if whileStmt, ok := list[i].(*js.WhileStmt); ok {
if forStmt.Init == nil {
forStmt.Init = left
j--
} else {
// TODO: merge with expressions if they define the declarations
}
} else if whileStmt, ok := list[i].(*js.WhileStmt); ok && left.TokenType == js.VarToken {
// TODO: only merge statements that don't have 'in' or 'of' keywords (slow to check?)
var body js.BlockStmt
if blockStmt, ok := whileStmt.Body.(*js.BlockStmt); ok {
Expand Down
31 changes: 18 additions & 13 deletions js/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,24 @@ func (m *jsMinifier) hoistVars(body *js.BlockStmt) *js.VarDecl {
var decl *js.VarDecl
if varDecl, ok := body.List[0].(*js.VarDecl); ok && varDecl.TokenType == js.VarToken {
decl = varDecl
//} else if forStmt, ok := body.List[0].(*js.ForStmt); ok && forStmt.Init != nil {
// if varDecl, ok := forStmt.Init.(*js.VarDecl); ok && varDecl.TokenType == js.VarToken {
// decl = varDecl
// }
//} else if whileStmt, ok := body.List[0].(*js.WhileStmt); ok {
// decl = &js.VarDecl{js.VarToken, nil}
// var forBody js.BlockStmt
// if blockStmt, ok := whileStmt.Body.(*js.BlockStmt); ok {
// forBody = *blockStmt
// } else {
// forBody.List = []js.IStmt{whileStmt.Body}
// }
// body.List[0] = &js.ForStmt{decl, whileStmt.Cond, nil, forBody}
} else if forStmt, ok := body.List[0].(*js.ForStmt); ok {
// TODO: only merge statements that don't have 'in' or 'of' keywords (slow to check?)
if forStmt.Init == nil {
decl = &js.VarDecl{js.VarToken, nil}
forStmt.Init = decl
} else if varDecl, ok := forStmt.Init.(*js.VarDecl); ok && varDecl.TokenType == js.VarToken {
decl = varDecl
}
} else if whileStmt, ok := body.List[0].(*js.WhileStmt); ok {
// TODO: only merge statements that don't have 'in' or 'of' keywords (slow to check?)
decl = &js.VarDecl{js.VarToken, nil}
var forBody js.BlockStmt
if blockStmt, ok := whileStmt.Body.(*js.BlockStmt); ok {
forBody = *blockStmt
} else {
forBody.List = []js.IStmt{whileStmt.Body}
}
body.List[0] = &js.ForStmt{decl, whileStmt.Cond, nil, forBody}
}
if decl != nil {
// original declarations
Expand Down