uglify-js
Advanced tools
Comparing version 2.4.0 to 2.4.1
@@ -200,2 +200,6 @@ /*********************************************************************** | ||
var AST_IterationStatement = DEFNODE("IterationStatement", null, { | ||
$documentation: "Internal class. All loops inherit from it." | ||
}, AST_StatementWithBody); | ||
var AST_DWLoop = DEFNODE("DWLoop", "condition", { | ||
@@ -212,3 +216,3 @@ $documentation: "Base class for do/while statements", | ||
} | ||
}, AST_StatementWithBody); | ||
}, AST_IterationStatement); | ||
@@ -238,3 +242,3 @@ var AST_Do = DEFNODE("Do", null, { | ||
} | ||
}, AST_StatementWithBody); | ||
}, AST_IterationStatement); | ||
@@ -255,3 +259,3 @@ var AST_ForIn = DEFNODE("ForIn", "init name object", { | ||
} | ||
}, AST_StatementWithBody); | ||
}, AST_IterationStatement); | ||
@@ -828,3 +832,7 @@ var AST_With = DEFNODE("With", "expression", { | ||
$propdoc: { | ||
references: "[AST_LabelRef*] a list of nodes referring to this label" | ||
references: "[AST_LoopControl*] a list of nodes referring to this label" | ||
}, | ||
initialize: function() { | ||
this.references = []; | ||
this.thedef = this; | ||
} | ||
@@ -976,19 +984,13 @@ }, AST_Symbol); | ||
var stack = this.stack; | ||
if (label) { | ||
for (var i = stack.length; --i >= 0;) { | ||
var x = stack[i]; | ||
if (x instanceof AST_LabeledStatement && x.label.name == label.name) { | ||
return x.body; | ||
} | ||
if (label) for (var i = stack.length; --i >= 0;) { | ||
var x = stack[i]; | ||
if (x instanceof AST_LabeledStatement && x.label.name == label.name) { | ||
return x.body; | ||
} | ||
} else { | ||
for (var i = stack.length; --i >= 0;) { | ||
var x = stack[i]; | ||
if (x instanceof AST_Switch | ||
|| x instanceof AST_For | ||
|| x instanceof AST_ForIn | ||
|| x instanceof AST_DWLoop) return x; | ||
} | ||
} else for (var i = stack.length; --i >= 0;) { | ||
var x = stack[i]; | ||
if (x instanceof AST_Switch || x instanceof AST_IterationStatement) | ||
return x; | ||
} | ||
} | ||
}; |
@@ -402,3 +402,3 @@ /*********************************************************************** | ||
comments.forEach(function(c){ | ||
if (c.type == "comment1") { | ||
if (/comment[134]/.test(c.type)) { | ||
output.print("//" + c.value + "\n"); | ||
@@ -993,3 +993,14 @@ output.indent(); | ||
output.print(self.operator); | ||
output.space(); | ||
if (self.operator == "<" | ||
&& self.right instanceof AST_UnaryPrefix | ||
&& self.right.operator == "!" | ||
&& self.right.expression instanceof AST_UnaryPrefix | ||
&& self.right.expression.operator == "--") { | ||
// space is mandatory to avoid outputting <!-- | ||
// http://javascript.spec.whatwg.org/#comment-syntax | ||
output.print(" "); | ||
} else { | ||
// the space is optional depending on "beautify" | ||
output.space(); | ||
} | ||
self.right.print(output); | ||
@@ -996,0 +1007,0 @@ }); |
100
lib/parse.js
@@ -173,3 +173,3 @@ /*********************************************************************** | ||
if (i == 0) return false; | ||
if (is_digit(str.charCodeAt(0))) return false; | ||
if (!is_identifier_start(str.charCodeAt(0))) return false; | ||
while (--i >= 0) { | ||
@@ -214,3 +214,3 @@ if (!is_identifier_char(str.charAt(i))) | ||
function tokenizer($TEXT, filename) { | ||
function tokenizer($TEXT, filename, html5_comments) { | ||
@@ -247,2 +247,10 @@ var S = { | ||
function forward(i) { | ||
while (i-- > 0) next(); | ||
}; | ||
function looking_at(str) { | ||
return S.text.substr(S.pos, str.length) == str; | ||
}; | ||
function find(what, signal_eof) { | ||
@@ -260,2 +268,3 @@ var pos = S.text.indexOf(what, S.pos); | ||
var prev_was_dot = false; | ||
function token(type, value, is_comment) { | ||
@@ -265,2 +274,3 @@ S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) || | ||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value))); | ||
prev_was_dot = (type == "punc" && value == "."); | ||
var ret = { | ||
@@ -387,4 +397,4 @@ type : type, | ||
function read_line_comment() { | ||
next(); | ||
function skip_line_comment(type) { | ||
var regex_allowed = S.regex_allowed; | ||
var i = find("\n"), ret; | ||
@@ -398,7 +408,9 @@ if (i == -1) { | ||
} | ||
return token("comment1", ret, true); | ||
S.comments_before.push(token(type, ret, true)); | ||
S.regex_allowed = regex_allowed; | ||
return next_token(); | ||
}; | ||
var read_multiline_comment = with_eof_error("Unterminated multiline comment", function(){ | ||
next(); | ||
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){ | ||
var regex_allowed = S.regex_allowed; | ||
var i = find("*/", true); | ||
@@ -413,4 +425,7 @@ var text = S.text.substring(S.pos, i); | ||
S.col += 2; | ||
S.newline_before = S.newline_before || text.indexOf("\n") >= 0; | ||
return token("comment2", text, true); | ||
var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0; | ||
S.comments_before.push(token("comment2", text, true)); | ||
S.regex_allowed = regex_allowed; | ||
S.newline_before = nlb; | ||
return next_token(); | ||
}); | ||
@@ -479,12 +494,9 @@ | ||
next(); | ||
var regex_allowed = S.regex_allowed; | ||
switch (peek()) { | ||
case "/": | ||
S.comments_before.push(read_line_comment()); | ||
S.regex_allowed = regex_allowed; | ||
return next_token(); | ||
next(); | ||
return skip_line_comment("comment1"); | ||
case "*": | ||
S.comments_before.push(read_multiline_comment()); | ||
S.regex_allowed = regex_allowed; | ||
return next_token(); | ||
next(); | ||
return skip_multiline_comment(); | ||
} | ||
@@ -503,2 +515,3 @@ return S.regex_allowed ? read_regexp("") : read_operator("/"); | ||
var word = read_name(); | ||
if (prev_was_dot) return token("name", word); | ||
return KEYWORDS_ATOM(word) ? token("atom", word) | ||
@@ -526,2 +539,12 @@ : !KEYWORDS(word) ? token("name", word) | ||
start_token(); | ||
if (html5_comments) { | ||
if (looking_at("<!--")) { | ||
forward(4); | ||
return skip_line_comment("comment3"); | ||
} | ||
if (looking_at("-->") && S.newline_before) { | ||
forward(3); | ||
return skip_line_comment("comment4"); | ||
} | ||
} | ||
var ch = peek(); | ||
@@ -602,10 +625,14 @@ if (!ch) return token("eof"); | ||
options = defaults(options, { | ||
strict : false, | ||
filename : null, | ||
toplevel : null, | ||
expression : false | ||
strict : false, | ||
filename : null, | ||
toplevel : null, | ||
expression : false, | ||
html5_comments : true, | ||
}); | ||
var S = { | ||
input : typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT, | ||
input : (typeof $TEXT == "string" | ||
? tokenizer($TEXT, options.filename, | ||
options.html5_comments) | ||
: $TEXT), | ||
token : null, | ||
@@ -703,4 +730,3 @@ prev : null, | ||
var statement = embed_tokens(function() { | ||
var tmp; | ||
function handle_regexp() { | ||
if (is("operator", "/") || is("operator", "/=")) { | ||
@@ -710,2 +736,7 @@ S.peeked = null; | ||
} | ||
}; | ||
var statement = embed_tokens(function() { | ||
var tmp; | ||
handle_regexp(); | ||
switch (S.token.type) { | ||
@@ -838,2 +869,14 @@ case "string": | ||
S.labels.pop(); | ||
if (!(stat instanceof AST_IterationStatement)) { | ||
// check for `continue` that refers to this label. | ||
// those should be reported as syntax errors. | ||
// https://github.com/mishoo/UglifyJS2/issues/287 | ||
label.references.forEach(function(ref){ | ||
if (ref instanceof AST_Continue) { | ||
ref = ref.label.start; | ||
croak("Continue label `" + label.name + "` refers to non-IterationStatement.", | ||
ref.line, ref.col, ref.pos); | ||
} | ||
}); | ||
} | ||
return new AST_LabeledStatement({ body: stat, label: label }); | ||
@@ -847,3 +890,3 @@ }; | ||
function break_cont(type) { | ||
var label = null; | ||
var label = null, ldef; | ||
if (!can_insert_semicolon()) { | ||
@@ -853,4 +896,6 @@ label = as_symbol(AST_LabelRef, true); | ||
if (label != null) { | ||
if (!find_if(function(l){ return l.name == label.name }, S.labels)) | ||
ldef = find_if(function(l){ return l.name == label.name }, S.labels); | ||
if (!ldef) | ||
croak("Undefined label " + label.name); | ||
label.thedef = ldef; | ||
} | ||
@@ -860,3 +905,5 @@ else if (S.in_loop == 0) | ||
semicolon(); | ||
return new type({ label: label }); | ||
var stat = new type({ label: label }); | ||
if (ldef) ldef.references.push(stat); | ||
return stat; | ||
}; | ||
@@ -1300,2 +1347,3 @@ | ||
next(); | ||
handle_regexp(); | ||
var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); | ||
@@ -1302,0 +1350,0 @@ ex.start = start; |
@@ -85,3 +85,2 @@ /*********************************************************************** | ||
var scope = self.parent_scope = null; | ||
var labels = new Dictionary(); | ||
var nesting = 0; | ||
@@ -92,8 +91,5 @@ var tw = new TreeWalker(function(node, descend){ | ||
var save_scope = node.parent_scope = scope; | ||
var save_labels = labels; | ||
++nesting; | ||
scope = node; | ||
labels = new Dictionary(); | ||
descend(); | ||
labels = save_labels; | ||
scope = save_scope; | ||
@@ -113,18 +109,5 @@ --nesting; | ||
} | ||
if (node instanceof AST_LabeledStatement) { | ||
var l = node.label; | ||
if (labels.has(l.name)) | ||
throw new Error(string_template("Label {name} defined twice", l)); | ||
labels.set(l.name, l); | ||
descend(); | ||
labels.del(l.name); | ||
return true; // no descend again | ||
} | ||
if (node instanceof AST_Symbol) { | ||
node.scope = scope; | ||
} | ||
if (node instanceof AST_Label) { | ||
node.thedef = node; | ||
node.init_scope_vars(); | ||
} | ||
if (node instanceof AST_SymbolLambda) { | ||
@@ -156,11 +139,2 @@ scope.def_function(node); | ||
} | ||
if (node instanceof AST_LabelRef) { | ||
var sym = labels.get(node.name); | ||
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { | ||
name: node.name, | ||
line: node.start.line, | ||
col: node.start.col | ||
})); | ||
node.thedef = sym; | ||
} | ||
}); | ||
@@ -180,6 +154,2 @@ self.walk(tw); | ||
} | ||
if (node instanceof AST_LabelRef) { | ||
node.reference(); | ||
return true; | ||
} | ||
if (node instanceof AST_SymbolRef) { | ||
@@ -203,3 +173,3 @@ var name = node.name; | ||
} | ||
if (name == "arguments") { | ||
if (func && name == "arguments") { | ||
func.uses_arguments = true; | ||
@@ -250,10 +220,2 @@ } | ||
AST_Label.DEFMETHOD("init_scope_vars", function(){ | ||
this.references = []; | ||
}); | ||
AST_LabelRef.DEFMETHOD("reference", function(){ | ||
this.thedef.references.push(this); | ||
}); | ||
AST_Scope.DEFMETHOD("find_variable", function(name){ | ||
@@ -260,0 +222,0 @@ if (name instanceof AST_Symbol) name = name.name; |
@@ -6,3 +6,3 @@ { | ||
"main": "tools/node.js", | ||
"version": "2.4.0", | ||
"version": "2.4.1", | ||
"engines": { "node" : ">=0.4.0" }, | ||
@@ -9,0 +9,0 @@ "maintainers": [{ |
@@ -187,27 +187,44 @@ UglifyJS 2 | ||
- `sequences` -- join consecutive simple statements using the comma operator | ||
- `properties` -- rewrite property access using the dot notation, for | ||
example `foo["bar"] → foo.bar` | ||
- `dead_code` -- remove unreachable code | ||
- `drop_debugger` -- remove `debugger;` statements | ||
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below) | ||
- `conditionals` -- apply optimizations for `if`-s and conditional | ||
expressions | ||
- `comparisons` -- apply certain optimizations to binary nodes, for example: | ||
`!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes, | ||
e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc. | ||
- `evaluate` -- attempt to evaluate constant expressions | ||
- `booleans` -- various optimizations for boolean context, for example `!!a | ||
? b : c → a ? b : c` | ||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can | ||
statically determine the condition | ||
- `unused` -- drop unreferenced functions and variables | ||
- `hoist_funs` -- hoist function declarations | ||
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false` | ||
by default because it seems to increase the size of the output in general) | ||
- `if_return` -- optimizations for if/return and if/continue | ||
- `join_vars` -- join consecutive `var` statements | ||
- `cascade` -- small optimization for sequences, transform `x, x` into `x` | ||
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" | ||
@@ -217,2 +234,17 @@ where the return value is discarded, to avoid the parens that the | ||
- `pure_getters` -- the default is `false`. If you pass `true` for | ||
this, UglifyJS will assume that object property access | ||
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. | ||
- `pure_funcs` -- default `null`. You can pass an array of names and | ||
UglifyJS will assume that those functions do not produce side | ||
effects. DANGER: will not check if the name is redefined in scope. | ||
An example case here, for instance `var q = Math.floor(a/b)`. If | ||
variable `q` is not used elsewhere, UglifyJS will drop it, but will | ||
still keep the `Math.floor(a/b)`, not knowing what it does. You can | ||
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this | ||
function won't produce any side effect, in which case the whole | ||
statement would get discarded. The current implementation adds some | ||
overhead (compression will be slower). | ||
### The `unsafe` option | ||
@@ -219,0 +251,0 @@ |
@@ -15,1 +15,61 @@ holes_and_undefined: { | ||
} | ||
constant_join: { | ||
options = { | ||
unsafe : true, | ||
evaluate : true | ||
}; | ||
input: { | ||
var a = [ "foo", "bar", "baz" ].join(""); | ||
var a1 = [ "foo", "bar", "baz" ].join(); | ||
var b = [ "foo", 1, 2, 3, "bar" ].join(""); | ||
var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join(""); | ||
var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join(""); | ||
var c2 = [ 1, 2, "foo", "bar", baz() ].join(""); | ||
var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-"); | ||
var e = [].join(foo + bar); | ||
var f = [].join(""); | ||
var g = [].join("foo"); | ||
} | ||
expect: { | ||
var a = "foobarbaz"; | ||
var a1 = "foo,bar,baz"; | ||
var b = "foo123bar"; | ||
var c = boo() + "foo123bar" + bar(); | ||
var c1 = "" + boo() + bar() + "foo123bar" + bar(); | ||
var c2 = "12foobar" + baz(); | ||
var d = "foo-3bar-baz"; | ||
var e = [].join(foo + bar); | ||
var f = ""; | ||
var g = ""; | ||
} | ||
} | ||
constant_join_2: { | ||
options = { | ||
unsafe : true, | ||
evaluate : true | ||
}; | ||
input: { | ||
var a = [ "foo", "bar", boo(), "baz", "x", "y" ].join(""); | ||
var b = [ "foo", "bar", boo(), "baz", "x", "y" ].join("-"); | ||
var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator"); | ||
var d = [ "foo", "bar", boo(), | ||
[ "foo", 1, 2, 3, "bar" ].join("+"), | ||
"baz", "x", "y" ].join("-"); | ||
var e = [ "foo", "bar", boo(), | ||
[ "foo", 1, 2, 3, "bar" ].join("+"), | ||
"baz", "x", "y" ].join("really-long-separator"); | ||
var f = [ "str", "str" + variable, "foo", "bar", "moo" + foo ].join(""); | ||
} | ||
expect: { | ||
var a = "foobar" + boo() + "bazxy"; | ||
var b = [ "foo-bar", boo(), "baz-x-y" ].join("-"); | ||
var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator"); | ||
var d = [ "foo-bar", boo(), "foo+1+2+3+bar-baz-x-y" ].join("-"); | ||
var e = [ "foo", "bar", boo(), | ||
"foo+1+2+3+bar", | ||
"baz", "x", "y" ].join("really-long-separator"); | ||
var f = "strstr" + variable + "foobarmoo" + foo; | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
355231
38
8509
626