Compare commits

...

30 Commits

Author SHA1 Message Date
Alex Lam S.L
a10c7793bb v3.12.4 2021-01-01 08:47:24 +08:00
Alex Lam S.L
0b7d65d331 fix corner case with arguments (#4486)
fixes #4485
2020-12-31 14:55:05 +08:00
Alex Lam S.L
8b954b022b fix corner case with default values (#4484)
fixes #4483
2020-12-31 01:47:00 +08:00
Alex Lam S.L
0013cbf91f improve false positive detection in ufuzz (#4482) 2020-12-30 21:53:03 +08:00
Alex Lam S.L
1956edd503 fix corner cases with arguments (#4481)
fixes #4480
2020-12-30 00:22:03 +08:00
Alex Lam S.L
560ccc1221 enhance reduce_vars (#4479) 2020-12-29 19:43:12 +08:00
Alex Lam S.L
10a71c182b fix corner case in arguments (#4477)
fixes #4476
2020-12-29 18:58:29 +08:00
Alex Lam S.L
ddc0ed7072 expand test options (#4475)
- fix corner cases in `hoist_vars` & `keep_fnames`
2020-12-29 06:17:52 +08:00
Alex Lam S.L
c00efe56f4 workaround asynchronous tty bugs on Node.js (#4473) 2020-12-28 13:32:07 +08:00
Alex Lam S.L
28bcdbd7df fix corner case in inline (#4472)
fixes #4471
2020-12-28 10:05:59 +08:00
Alex Lam S.L
6a8aed2049 fix corner case in unused (#4469)
fixes #4468
2020-12-27 20:06:50 +08:00
Alex Lam S.L
a8785fb694 workaround v8 bug with labels (#4467)
closes #4466
2020-12-27 13:32:18 +08:00
Alex Lam S.L
dd6d7b3d88 workaround schedule delays on GitHub Actions (#4463) 2020-12-26 17:27:03 +08:00
Alex Lam S.L
94f3819dc6 fix corner case in reduce_vars & unused (#4465)
fixes #4464
2020-12-26 16:52:16 +08:00
Alex Lam S.L
be1f5199f4 fix corner cases in collapse_vars (#4462)
fixes #4460
fixes #4461
2020-12-26 13:40:31 +08:00
Alex Lam S.L
95aea0e33c fix corner case in reduce_vars (#4459)
fixes #4458
2020-12-25 22:50:11 +08:00
Alex Lam S.L
a1b2735dd8 fix corner case in unused (#4457)
fixes #4456
2020-12-25 20:10:58 +08:00
Alex Lam S.L
f345175bc2 fix corner case in merge_vars (#4455)
fixes #4454
2020-12-25 19:27:05 +08:00
Alex Lam S.L
bb45f48ab7 workaround v8 heisenbug (#4453) 2020-12-25 13:14:36 +08:00
Alex Lam S.L
b2f27fd873 fix corner case in functions & reduce_vars (#4452)
fixes #4451
2020-12-25 08:38:24 +08:00
Alex Lam S.L
ced32f9bd8 enhance default_values (#4450) 2020-12-25 07:31:34 +08:00
Alex Lam S.L
dfc3ec9cef fix corner case in pure_getters (#4449)
fixes #4448
2020-12-25 03:58:23 +08:00
Alex Lam S.L
1896694532 fix & enhance collapse_vars (#4447)
fixes #4446
2020-12-24 17:02:18 +08:00
Alex Lam S.L
5f269cd573 fix corner case in collapse_vars (#4445)
fixes #4444
2020-12-24 10:56:22 +08:00
Alex Lam S.L
6988cd9558 replace keep_fargs default to false (#4443) 2020-12-24 09:56:02 +08:00
Alex Lam S.L
2390fae5c4 support default values (#4442) 2020-12-24 06:22:55 +08:00
Alex Lam S.L
56fce2131c fix corner case in pure_getters (#4441)
fixes #4440
2020-12-24 04:09:09 +08:00
Alex Lam S.L
7e575e9d7f fix corner case in if_return (#4439)
fixes #4438
2020-12-24 04:08:57 +08:00
Alex Lam S.L
cb4a02949e fix corner case with NaN (#4437)
fixes #4436
2020-12-23 07:01:50 +08:00
Alex Lam S.L
f85a206b9e fix corner case when parsing expression (#4435) 2020-12-23 02:16:04 +08:00
51 changed files with 3304 additions and 781 deletions

View File

@@ -7,13 +7,13 @@ jobs:
test:
strategy:
matrix:
node: [ "0.8", "0.10", "0.12", "4", "6", "8", "10", "12", latest ]
node: [ '0.8', '0.10', '0.12', '4', '6', '8', '10', '12', latest ]
os: [ ubuntu-latest, windows-latest ]
script: [ compress, mocha, release/benchmark, release/jetstream ]
exclude:
- node: "0.8"
- node: '0.8'
script: release/benchmark
- node: "0.8"
- node: '0.8'
script: release/jetstream
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
runs-on: ${{ matrix.os }}
@@ -29,7 +29,7 @@ jobs:
- name: Perform tests
shell: bash
run: |
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add $NODE && nvs use $NODE'; do
cd ~/.nvs
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done

View File

@@ -2,7 +2,7 @@ name: Fuzzing
on:
pull_request:
schedule:
- cron: "*/5 * * * *"
- cron: '*/5 * * * *'
env:
BASE_URL: https://api.github.com/repos/${{ github.repository }}
CAUSE: ${{ github.event_name }}
@@ -13,22 +13,39 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
name: ${{ matrix.os }}
include:
- node: latest
os: macos-latest
- node: '8'
os: ubuntu-latest
- node: '8'
os: ubuntu-latest
- node: '8'
os: windows-latest
- node: '8'
os: windows-latest
name: ${{ matrix.node }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
NODE: ${{ matrix.node }}
steps:
- uses: actions/checkout@v2
- name: Install GNU Core Utilities
if: ${{ startsWith(matrix.os, 'macos') }}
shell: bash
run: |
brew install coreutils
- name: Perform fuzzing
shell: bash
run: |
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 8 && nvs use 8'; do
git clone --branch v1.6.0 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add $NODE && nvs use $NODE'; do
cd ~/.nvs
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
cd -
done
. ~/.nvs/nvs.sh --version
nvs use 8
nvs use $NODE
node --version
npm config set audit false
npm config set optional false

View File

@@ -135,6 +135,10 @@ a double dash to prevent input files being used as option arguments:
`//# sourceMappingURL`.
--timings Display operations run time on STDERR.
--toplevel Compress and/or mangle variables in top level scope.
--v8 Support non-standard Chrome & Node.js
Equivalent to setting `v8: true` in `minify()`
for `mangle` and `output` options.
By default UglifyJS will not try to be v8-proof.
--verbose Print diagnostic messages.
--warn Print warning messages.
--webkit Support non-standard Safari/Webkit.
@@ -522,6 +526,8 @@ if (result.error) throw result.error;
- `toplevel` (default `false`) -- set to `true` if you wish to enable top level
variable and function name mangling and to drop unused variables and functions.
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs.
- `warnings` (default `false`) — pass `true` to return compressor warnings
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
@@ -638,6 +644,8 @@ to be `false` and all symbol names will be omitted.
- `dead_code` (default: `true`) -- remove unreachable code
- `default_values` (default: `true`) -- drop overshadowed default values
- `directives` (default: `true`) -- remove redundant or non-standard directives
- `drop_console` (default: `false`) -- Pass `true` to discard calls to
@@ -683,9 +691,9 @@ to be `false` and all symbol names will be omitted.
- `join_vars` (default: `true`) -- join consecutive `var` statements
- `keep_fargs` (default: `strict`) -- Discard unused function arguments. Code
which relies on `Function.length` will break if this is done indiscriminately,
i.e. when passing `true`. Pass `false` to always retain function arguments.
- `keep_fargs` (default: `false`) -- discard unused function arguments except
when unsafe to do so, e.g. code which relies on `Function.prototype.length`.
Pass `true` to always retain function arguments.
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on
@@ -919,8 +927,6 @@ can pass additional arguments that control the code output:
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
- `width` (default `80`) -- only takes effect when beautification is on, this
specifies an (orientative) line width that the beautifier will try to
obey. It refers to the width of the line text (excluding indentation).

View File

@@ -3,7 +3,7 @@
"use strict";
require("../tools/exit");
require("../tools/tty");
var fs = require("fs");
var info = require("../package.json");

View File

@@ -207,13 +207,23 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)"
}, AST_Statement);
function must_be_expression(node, prop) {
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
if (node[prop] instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
if (node[prop] instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
if (node[prop] instanceof AST_Statement && !is_function(node[prop])) {
throw new Error(prop + " cannot be AST_Statement");
function validate_expression(value, prop, multiple, allow_spread, allow_hole) {
multiple = multiple ? "contain" : "be";
if (!(value instanceof AST_Node)) throw new Error(prop + " must " + multiple + " AST_Node");
if (value instanceof AST_DefaultValue) throw new Error(prop + " cannot " + multiple + " AST_DefaultValue");
if (value instanceof AST_Destructured) throw new Error(prop + " cannot " + multiple + " AST_Destructured");
if (value instanceof AST_Hole && !allow_hole) throw new Error(prop + " cannot " + multiple + " AST_Hole");
if (value instanceof AST_Spread && !allow_spread) throw new Error(prop + " cannot " + multiple + " AST_Spread");
if (value instanceof AST_Statement && !is_function(value)) {
throw new Error(prop + " cannot " + multiple + " AST_Statement");
}
if (value instanceof AST_SymbolDeclaration) {
throw new Error(prop + " cannot " + multiple + " AST_SymbolDeclaration");
}
}
function must_be_expression(node, prop) {
validate_expression(node[prop], prop);
}
var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
@@ -534,7 +544,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
this.argnames.forEach(function(node) {
validate_destructured(node, function(node) {
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
});
}, true);
});
},
}, AST_Scope);
@@ -838,7 +848,6 @@ var AST_Const = DEFNODE("Const", null, {
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
});
if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -851,7 +860,6 @@ var AST_Let = DEFNODE("Let", null, {
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
});
if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -864,7 +872,6 @@ var AST_Var = DEFNODE("Var", null, {
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
});
if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -873,7 +880,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: {
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer"
value: "[AST_Node?] initializer, or null of there's no initializer",
},
walk: function(visitor) {
var node = this;
@@ -882,18 +889,34 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
if (node.value) node.value.walk(visitor);
});
},
_validate: function() {
if (this.value != null) must_be_expression(this, "value");
},
});
/* -----[ OTHER ]----- */
var AST_DefaultValue = DEFNODE("DefaultValue", "name value", {
$documentation: "A default value declaration",
$propdoc: {
name: "[AST_Destructured|AST_SymbolDeclaration] name of the variable",
value: "[AST_Node] value to assign if variable is `undefined`",
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
node.name.walk(visitor);
node.value.walk(visitor);
});
},
_validate: function() {
must_be_expression(this, "value");
},
});
function must_be_expressions(node, prop, allow_spread, allow_hole) {
node[prop].forEach(function(node) {
if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
if (!allow_hole && node instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
if (!allow_spread && node instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
if (node instanceof AST_Statement && !is_function(node)) {
throw new Error(prop + " cannot contain AST_Statement");
}
validate_expression(node, prop, true, allow_spread, allow_hole);
});
}
@@ -1048,7 +1071,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
});
},
_validate: function() {
must_be_expression(this, "left");
if (!(this instanceof AST_Assign)) must_be_expression(this, "left");
if (typeof this.operator != "string") throw new Error("operator must be string");
must_be_expression(this, "right");
},
@@ -1131,12 +1154,13 @@ var AST_Destructured = DEFNODE("Destructured", null, {
$documentation: "Base class for destructured literal",
});
function validate_destructured(node, check) {
function validate_destructured(node, check, allow_default) {
if (node instanceof AST_DefaultValue && allow_default) return validate_destructured(node.name, check);
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
if (!(node instanceof AST_Hole)) validate_destructured(node, check);
if (!(node instanceof AST_Hole)) validate_destructured(node, check, true);
});
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
validate_destructured(prop.value, check);
validate_destructured(prop.value, check, true);
});
check(node);
}
@@ -1174,7 +1198,7 @@ var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
must_be_expression(this, "key");
}
must_be_expression(this, "value");
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
},
});

File diff suppressed because it is too large Load Diff

View File

@@ -87,6 +87,7 @@ function minify(files, options) {
sourceMap: false,
timings: false,
toplevel: false,
v8: false,
validate: false,
warnings: false,
webkit: false,
@@ -102,6 +103,7 @@ function minify(files, options) {
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("v8", options, [ "mangle", "output" ]);
set_shorthand("webkit", options, [ "mangle", "output" ]);
var quoted_props;
if (options.mangle) {
@@ -113,6 +115,7 @@ function minify(files, options) {
properties: false,
reserved: [],
toplevel: false,
v8: false,
webkit: false,
}, true);
if (options.mangle.properties) {

View File

@@ -702,6 +702,8 @@ function OutputStream(options) {
// (false, true) ? (a = 10, b = 20) : (c = 30)
// ==> 20 (side effect, set a := 10 and b := 20)
|| p instanceof AST_Conditional
// [ a = (1, 2) ] = [] ==> a == 2
|| p instanceof AST_DefaultValue
// { [(1, 2)]: 3 }[2] ==> 3
// { foo: (1, 2) }.foo ==> 2
|| p instanceof AST_DestructuredKeyVal
@@ -1218,6 +1220,15 @@ function OutputStream(options) {
}
});
DEFPRINT(AST_DefaultValue, function(output) {
var self = this;
self.name.print(output);
output.space();
output.print("=");
output.space();
self.value.print(output);
});
/* -----[ other expressions ]----- */
function print_call_args(self, output) {
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {

View File

@@ -737,7 +737,7 @@ function parse($TEXT, options) {
function semicolon(optional) {
if (is("punc", ";")) next();
else if (!optional && !can_insert_semicolon()) expect_token("punc", ";");
else if (!optional && !can_insert_semicolon()) expect(";");
}
function parenthesised() {
@@ -1041,11 +1041,30 @@ function parse($TEXT, options) {
function to_funarg(node) {
if (node instanceof AST_Array) return new AST_DestructuredArray({
start: node.start,
elements: node.elements.map(function(node) {
return node instanceof AST_Hole ? node : to_funarg(node);
}),
elements: node.elements.map(to_funarg),
end: node.end,
});
if (node instanceof AST_Assign) return new AST_DefaultValue({
start: node.start,
name: to_funarg(node.left),
value: node.right,
end: node.end,
});
if (node instanceof AST_DefaultValue) {
node.name = to_funarg(node.name);
return node;
}
if (node instanceof AST_DestructuredArray) {
node.elements = node.elements.map(to_funarg);
return node;
}
if (node instanceof AST_DestructuredObject) {
node.properties.forEach(function(prop) {
prop.value = to_funarg(prop.value);
});
return node;
}
if (node instanceof AST_Hole) return node;
if (node instanceof AST_Object) return new AST_DestructuredObject({
start: node.start,
properties: node.properties.map(function(prop) {
@@ -1122,7 +1141,7 @@ function parse($TEXT, options) {
var was_funarg = S.in_funarg;
S.in_funarg = S.in_function;
var argnames = expr_list(")", !options.strict, false, function() {
return maybe_destructured(AST_SymbolFunarg);
return maybe_default(AST_SymbolFunarg);
});
S.in_funarg = was_funarg;
var loop = S.in_loop;
@@ -1166,7 +1185,7 @@ function parse($TEXT, options) {
expect("{");
var a = [];
while (!is("punc", "}")) {
if (is("eof")) expect_token("punc", "}");
if (is("eof")) expect("}");
a.push(statement());
}
next();
@@ -1177,7 +1196,7 @@ function parse($TEXT, options) {
expect("{");
var a = [], branch, cur, default_branch, tmp;
while (!is("punc", "}")) {
if (is("eof")) expect_token("punc", "}");
if (is("eof")) expect("}");
if (is("keyword", "case")) {
if (branch) branch.end = prev();
cur = [];
@@ -1468,6 +1487,32 @@ function parse($TEXT, options) {
}));
continue;
}
if (is_token(peek(), "operator", "=")) {
var name = as_symbol(AST_SymbolRef);
next();
a.push(new AST_ObjectKeyVal({
start: start,
key: start.value,
value: new AST_Assign({
start: start,
left: name,
operator: "=",
right: maybe_assign(),
end: prev(),
}),
end: prev(),
}));
continue;
}
if (is_token(peek(), "punc", ",") || is_token(peek(), "punc", "}")) {
a.push(new AST_ObjectKeyVal({
start: start,
key: start.value,
value: as_symbol(AST_SymbolRef),
end: prev(),
}));
continue;
}
var key = as_property_key();
if (is("punc", "(")) {
var func_start = S.token;
@@ -1492,15 +1537,6 @@ function parse($TEXT, options) {
}));
continue;
}
if (is("punc", ",") || is("punc", "}")) {
a.push(new AST_ObjectKeyVal({
start: start,
key: key,
value: _make_symbol(AST_SymbolRef, start),
end: prev(),
}));
continue;
}
if (start.type == "name") switch (key) {
case "async":
key = as_property_key();
@@ -1561,9 +1597,8 @@ function parse($TEXT, options) {
}
function as_name() {
if (!is("name")) expect_token("name");
var name = S.token.value;
next();
expect_token("name");
return name;
}
@@ -1602,7 +1637,7 @@ function parse($TEXT, options) {
return new AST_DestructuredArray({
start: start,
elements: expr_list("]", !options.strict, true, function() {
return maybe_destructured(type);
return maybe_default(type);
}),
end: prev(),
});
@@ -1621,15 +1656,25 @@ function parse($TEXT, options) {
a.push(new AST_DestructuredKeyVal({
start: key_start,
key: key,
value: maybe_destructured(type),
value: maybe_default(type),
end: prev(),
}));
continue;
}
var name = as_symbol(type);
if (is("operator", "=")) {
next();
name = new AST_DefaultValue({
start: name.start,
name: name,
value: maybe_assign(),
end: prev(),
});
}
a.push(new AST_DestructuredKeyVal({
start: key_start,
key: key_start.value,
value: as_symbol(type),
value: name,
end: prev(),
}));
}
@@ -1643,6 +1688,19 @@ function parse($TEXT, options) {
return as_symbol(type);
}
function maybe_default(type) {
var start = S.token;
var name = maybe_destructured(type);
if (!is("operator", "=")) return name;
next();
return new AST_DefaultValue({
start: start,
name: name,
value: maybe_assign(),
end: prev(),
});
}
function mark_pure(call) {
var start = call.start;
var comments = start.comments_before;
@@ -1789,20 +1847,34 @@ function parse($TEXT, options) {
if (node instanceof AST_Array) {
var elements = node.elements.map(to_destructured);
return all(elements, function(node) {
return node instanceof AST_Destructured || node instanceof AST_Hole || is_assignable(node);
return node instanceof AST_DefaultValue
|| node instanceof AST_Destructured
|| node instanceof AST_Hole
|| is_assignable(node);
}) ? new AST_DestructuredArray({
start: node.start,
elements: elements,
end: node.end,
}) : node;
}
if (node instanceof AST_Assign) {
var name = to_destructured(node.left);
return name instanceof AST_Destructured || is_assignable(name) ? new AST_DefaultValue({
start: node.start,
name: name,
value: node.right,
end: node.end,
}) : node;
}
if (!(node instanceof AST_Object)) return node;
var props = [];
for (var i = 0; i < node.properties.length; i++) {
var prop = node.properties[i];
if (!(prop instanceof AST_ObjectKeyVal)) return node;
var value = to_destructured(prop.value);
if (!(value instanceof AST_Destructured || is_assignable(value))) return node;
if (!(value instanceof AST_DefaultValue || value instanceof AST_Destructured || is_assignable(value))) {
return node;
}
props.push(new AST_DestructuredKeyVal({
start: prop.start,
key: prop.key,
@@ -1861,7 +1933,9 @@ function parse($TEXT, options) {
if (options.expression) {
handle_regexp();
return expression();
var exp = expression();
expect_token("eof");
return exp;
}
return function() {

View File

@@ -265,10 +265,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}
if (!sym) {
sym = self.def_global(node);
} else if (name == "arguments"
&& sym.orig[0] instanceof AST_SymbolFunarg
&& !(sym.orig[1] instanceof AST_SymbolFunarg)
&& !(sym.scope instanceof AST_Arrow)) {
} else if (name == "arguments" && is_arguments(sym)) {
var parent = tw.parent();
if (parent instanceof AST_Assign && parent.left === node
|| parent instanceof AST_Unary && unary_side_effects[parent.operator]) {
@@ -297,6 +294,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
node.reference(options);
return true;
}
if (node instanceof AST_VarDef) {
if (node.value && node.name.name == "arguments") {
var sym = node.name.scope.resolve().find_variable("arguments");
if (sym && is_arguments(sym)) sym.scope.uses_arguments = 3;
}
return;
}
});
self.walk(tw);
@@ -322,6 +326,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
}
}));
function is_arguments(sym) {
return sym.orig[0] instanceof AST_SymbolFunarg
&& !(sym.orig[1] instanceof AST_SymbolFunarg || sym.orig[2] instanceof AST_SymbolFunarg)
&& !(sym.scope instanceof AST_Arrow);
}
function redefine(node, scope) {
var name = node.name;
var old_def = node.thedef;
@@ -512,6 +522,7 @@ function _default_mangler_options(options) {
keep_fnames : false,
reserved : [],
toplevel : false,
v8 : false,
webkit : false,
});
if (!Array.isArray(options.reserved)) options.reserved = [];
@@ -543,7 +554,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
// lname is incremented when we get to the AST_Label
var save_nesting = lname;
descend();
lname = save_nesting;
if (!options.v8 || !in_label(tw)) lname = save_nesting;
return true;
}
if (node instanceof AST_BlockScope) {
@@ -616,6 +627,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
sym.thedef = def;
}
}
function in_label(tw) {
var level = 0, parent;
while (parent = tw.parent(level++)) {
if (parent instanceof AST_Block) return parent instanceof AST_Toplevel && !options.toplevel;
if (parent instanceof AST_LabeledStatement) return true;
}
}
});
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {

View File

@@ -126,6 +126,10 @@ TreeTransformer.prototype = new TreeWalker;
self.name = self.name.transform(tw);
if (self.value) self.value = self.value.transform(tw);
});
DEF(AST_DefaultValue, function(self, tw) {
self.name = self.name.transform(tw);
self.value = self.value.transform(tw);
});
DEF(AST_Lambda, function(self, tw) {
if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw);

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.12.3",
"version": "3.12.4",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -1,6 +1,6 @@
"use strict";
require("../tools/exit");
require("../tools/tty");
var assert = require("assert");
var child_process = require("child_process");

View File

@@ -78,7 +78,7 @@ replace_index_strict: {
]
}
replace_index_keep_fargs: {
replace_index_drop_fargs_1: {
options = {
arguments: true,
evaluate: true,
@@ -101,6 +101,13 @@ replace_index_keep_fargs: {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments = {
1: "foo",
foo: "bar",
};
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
var arguments = [];
@@ -114,8 +121,15 @@ replace_index_keep_fargs: {
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
(function(argument_0, argument_1) {
var arguments;
console.log(argument_1, argument_1, arguments.foo);
})("bar", 42);
(function() {
var arguments = {
1: "foo",
foo: "bar",
};
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
@@ -125,10 +139,11 @@ replace_index_keep_fargs: {
"42 42 undefined",
"a a undefined",
"42 42 undefined",
"foo foo bar",
]
}
replace_index_keep_fargs_strict: {
replace_index_drop_fargs_2: {
options = {
arguments: true,
evaluate: true,
@@ -412,7 +427,7 @@ issue_3273_global_strict_reduce_vars: {
]
}
issue_3273_keep_fargs_false: {
issue_3273_drop_fargs_1: {
options = {
arguments: true,
keep_fargs: false,
@@ -435,10 +450,10 @@ issue_3273_keep_fargs_false: {
expect_stdout: "1"
}
issue_3273_keep_fargs_strict: {
issue_3273_drop_fargs_2: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
}
input: {
@@ -633,7 +648,7 @@ issue_3282_2_passes: {
issue_3420_1: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
console.log(function() {
@@ -655,7 +670,7 @@ issue_3420_1: {
issue_3420_2: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
var foo = function() {
@@ -675,7 +690,7 @@ issue_3420_2: {
issue_3420_3: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
"use strict";
@@ -697,7 +712,7 @@ issue_3420_3: {
issue_3420_4: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
!function() {
@@ -722,7 +737,7 @@ issue_3420_4: {
issue_3420_5: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
"use strict";
@@ -749,7 +764,7 @@ issue_3420_5: {
issue_3420_6: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
console.log(function() {
@@ -767,7 +782,7 @@ issue_3420_6: {
issue_3420_7: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
"use strict";
@@ -811,7 +826,7 @@ issue_4200: {
issue_4291_1: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
console.log(function() {
@@ -831,7 +846,7 @@ issue_4291_1: {
issue_4291_2: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
var a = function() {
@@ -855,7 +870,7 @@ issue_4291_2: {
issue_4397: {
options = {
arguments: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
console.log(typeof function() {

View File

@@ -419,7 +419,7 @@ collapse_value: {
options = {
arrows: true,
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -437,7 +437,7 @@ collapse_value: {
reduce_iife_1: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -587,3 +587,54 @@ issue_4401: {
]
node_version: ">=4"
}
issue_4448: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
var A;
try {
(arguments => {
arguments[0];
})(A);
} catch (e) {
console.log("PASS");
}
}
expect: {
var A;
try {
(arguments => {
arguments[0];
})(A);
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
node_version: ">=4"
}
issue_4476: {
options = {
arguments: true,
}
input: {
(function(a, b) {
(a => {
console.log(arguments[0], a);
})(b);
})("foo", "bar");
}
expect: {
(function(a, b) {
(a => {
console.log(arguments[0], a);
})(b);
})("foo", "bar");
}
expect_stdout: "foo bar"
node_version: ">=4"
}

View File

@@ -32,6 +32,54 @@ defun_name: {
node_version: ">=8"
}
drop_fname: {
rename = true
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
async function await() {
console.log("PASS");
}
await();
}
expect: {
(async function() {
console.log("PASS");
})();
}
expect_stdout: "PASS"
node_version: ">=8"
}
keep_fname: {
options = {
keep_fnames: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
async function await() {
console.log("PASS");
}
await();
}
expect: {
async function await() {
console.log("PASS");
}
await();
}
expect_stdout: "PASS"
node_version: ">=8"
}
nested_await: {
input: {
(async function() {
@@ -353,7 +401,7 @@ property_access_expression: {
reduce_iife_1: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -640,3 +688,59 @@ issue_4417: {
expect_stdout: "undefined"
node_version: ">=8"
}
issue_4454_1: {
rename = false
options = {
merge_vars: true,
}
input: {
function f(a) {
(async function(b = console.log(a)) {})();
var await = 42..toString();
console.log(await);
}
f("PASS");
}
expect: {
function f(a) {
(async function(b = console.log(a)) {})();
var await = 42..toString();
console.log(await);
}
f("PASS");
}
expect_stdout: [
"PASS",
"42",
]
node_version: ">=8"
}
issue_4454_2: {
rename = true
options = {
merge_vars: true,
}
input: {
function f(a) {
(async function(b = console.log(a)) {})();
var await = 42..toString();
console.log(await);
}
f("PASS");
}
expect: {
function f(b) {
(async function(c = console.log(b)) {})();
var b = 42..toString();
console.log(b);
}
f("PASS");
}
expect_stdout: [
"PASS",
"42",
]
node_version: ">=8"
}

View File

@@ -4273,8 +4273,8 @@ issue_2436_14: {
var b = {};
(function() {
a && function(c, d) {
console.log(c, d);
}(b, a);
console.log(b, d);
}(0, a);
})();
}
expect_stdout: true

View File

@@ -658,6 +658,30 @@ legacy_scope: {
expect_stdout: true
}
hoist_vars: {
options = {
hoist_vars: true,
}
input: {
{
const a = "FAIL";
var b = 42;
}
var a = "PASS";
console.log(a, b);
}
expect: {
var b;
{
const a = "FAIL";
b = 42;
}
var a = "PASS";
console.log(a, b);
}
expect_stdout: true
}
issue_4191: {
options = {
functions: true,

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,7 @@ redefine_arguments_2: {
redefine_arguments_3: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -259,7 +259,7 @@ funarg_side_effects_3: {
funarg_unused_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -318,7 +318,7 @@ funarg_unused_3: {
funarg_unused_4: {
options = {
keep_fargs: "strict",
keep_fargs: false,
pure_getters: "strict",
unused: true,
}
@@ -384,7 +384,7 @@ funarg_unused_6_inline: {
funarg_unused_6_keep_fargs: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -426,7 +426,7 @@ funarg_collapse_vars_1: {
funarg_collapse_vars_2: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -505,7 +505,7 @@ funarg_reduce_vars_1: {
funarg_reduce_vars_2: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
pure_getters: "strict",
reduce_vars: true,
unsafe: true,
@@ -691,6 +691,28 @@ funarg_inline: {
node_version: ">=6"
}
process_boolean_returns: {
options = {
booleans: true,
}
input: {
console.log(function({ length }) {
return length ? "FAIL" : "PASS";
}(function() {
return 42;
}));
}
expect: {
console.log(function({ length }) {
return length ? "FAIL" : "PASS";
}(function() {
return 42;
}));
}
expect_stdout: "PASS"
node_version: ">=6"
}
simple_const: {
options = {
evaluate: true,
@@ -1101,7 +1123,7 @@ join_vars: {
keep_fargs: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1336,6 +1358,24 @@ fn_name_unused: {
node_version: ">=6"
}
hoist_vars: {
options = {
hoist_vars: true,
}
input: {
var a = "PASS";
var [ b ] = [ 42 ];
console.log(a, b);
}
expect: {
var a = "PASS";
var [ b ] = [ 42 ];
console.log(a, b);
}
expect_stdout: "PASS 42"
node_version: ">=6"
}
issue_4280: {
options = {
evaluate: true,
@@ -1754,7 +1794,7 @@ issue_4319: {
issue_4321: {
options = {
inline: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
try {
@@ -2037,3 +2077,228 @@ issue_4425: {
expect_stdout: "PASS"
node_version: ">=8"
}
issue_4436_Infinity: {
options = {
unused: true,
}
input: {
console.log(function({
[delete Infinity]: a,
}) {
var Infinity;
return a;
}({
true: "FAIL",
false: "PASS",
}));
}
expect: {
console.log(function({
[delete Infinity]: a,
}) {
return a;
}({
true: "FAIL",
false: "PASS",
}));
}
expect_stdout: true
node_version: ">=6"
}
issue_4436_NaN: {
options = {
unused: true,
}
input: {
console.log(function({
[delete NaN]: a,
}) {
var NaN;
return a;
}({
true: "FAIL",
false: "PASS",
}));
}
expect: {
console.log(function({
[delete NaN]: a,
}) {
return a;
}({
true: "FAIL",
false: "PASS",
}));
}
expect_stdout: true
node_version: ">=6"
}
issue_4436_undefined: {
options = {
unused: true,
}
input: {
console.log(function({
[delete undefined]: a,
}) {
var undefined;
return a;
}({
true: "FAIL",
false: "PASS",
}));
}
expect: {
console.log(function({
[delete undefined]: a,
}) {
return a;
}({
true: "FAIL",
false: "PASS",
}));
}
expect_stdout: true
node_version: ">=6"
}
issue_4446: {
options = {
collapse_vars: true,
}
input: {
a = "PASS";
var a = [ a[0] ] = [ a ];
console.log(a[0]);
}
expect: {
a = "PASS";
var a = [ a[0] ] = [ a ];
console.log(a[0]);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4456: {
options = {
pure_getters: true,
unused: true,
}
input: {
var o = {
set p(v) {
console.log(v);
},
};
[ function() {
try {
return o;
} catch ({}) {}
}().p ] = [ "PASS" ];
}
expect: {
var o = {
set p(v) {
console.log(v);
},
};
[ function() {
try {
return o;
} catch ({}) {}
}().p ] = [ "PASS" ];
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4485_1: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
(function([]) {
var arguments;
try {
arguments.length;
} catch (e) {
console.log("PASS");
}
})([]);
}
expect: {
(function([]) {
var arguments;
try {
arguments.length;
} catch (e) {
console.log("PASS");
}
})([]);
}
expect_stdout: true
node_version: ">=6"
}
issue_4485_2: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
(function([]) {
var arguments = null;
try {
arguments.length;
} catch (e) {
console.log("PASS");
}
})([]);
}
expect: {
(function([]) {
var arguments = null;
try {
arguments.length;
} catch (e) {
console.log("PASS");
}
})([]);
}
expect_stdout: "PASS"
node_version: ">=6"
}
issue_4485_3: {
options = {
keep_fargs: false,
unused: true,
}
input: {
(function([]) {
var arguments;
try {
arguments.length;
} catch (e) {
console.log("PASS");
}
})([]);
}
expect: {
(function([]) {
var arguments;
try {
arguments.length;
} catch (e) {
console.log("PASS");
}
})([]);
}
expect_stdout: true
node_version: ">=6"
}

View File

@@ -4,15 +4,16 @@ unused_funarg_1: {
unused: true,
}
input: {
function f(a, b, c, d, e) {
console.log(function f(a, b, c, d, e) {
return a + b;
}
}(14, 28));
}
expect: {
function f(a, b) {
console.log(function(a, b) {
return a + b;
}
}(14, 28));
}
expect_stdout: "42"
}
unused_funarg_2: {
@@ -21,15 +22,16 @@ unused_funarg_2: {
unused: true,
}
input: {
function f(a, b, c, d, e) {
console.log(function f(a, b, c, d, e) {
return a + c;
}
}(14, 21, 28));
}
expect: {
function f(a, b, c) {
console.log(function(a, c) {
return a + c;
}
}(14, 28));
}
expect_stdout: "42"
}
unused_nested_function: {
@@ -357,37 +359,6 @@ drop_toplevel_vars: {
}
}
drop_toplevel_vars_fargs: {
options = {
keep_fargs: false,
toplevel: "vars",
unused: true,
}
input: {
var a, b = 1, c = g;
function f(d) {
return function() {
c = 2;
};
}
a = 2;
function g() {}
function h() {}
console.log(b = 3);
}
expect: {
function f() {
return function() {
2;
};
}
2;
function g() {}
function h() {}
console.log(3);
}
}
drop_toplevel_all: {
options = {
toplevel: true,
@@ -625,13 +596,14 @@ drop_fargs: {
unused: true,
}
input: {
function f(a) {
console.log(function f(a) {
var b = a;
}
}());
}
expect: {
function f() {}
console.log(function() {}());
}
expect_stdout: "undefined"
}
drop_fnames: {
@@ -2027,7 +1999,7 @@ issue_3192_1: {
issue_3192_2: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -2435,7 +2407,7 @@ issue_3673: {
issue_3746: {
options = {
keep_fargs: "strict",
keep_fargs: false,
side_effects: true,
unused: true,
}
@@ -2713,7 +2685,7 @@ issue_3956: {
issue_3962_1: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -2745,7 +2717,7 @@ issue_3962_1: {
issue_3962_2: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
side_effects: true,
toplevel: true,
@@ -2948,7 +2920,7 @@ issue_4133: {
issue_4144: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -3153,3 +3125,74 @@ issue_4413: {
}
expect_stdout: "0"
}
issue_4464_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
var a = function() {};
return [ arguments, a ];
}
console.log(typeof f()[1]);
}
expect: {
function f(a) {
a = function() {};
return [ arguments, a ];
}
console.log(typeof f()[1]);
}
expect_stdout: "function"
}
issue_4464_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
var a = function() {};
return [ arguments, a ];
}
console.log(typeof f(42)[0][0]);
}
expect: {
function f(a) {
a = function() {};
return [ arguments, a ];
}
console.log(typeof f(42)[0][0]);
}
expect_stdout: "function"
}
issue_4464_3: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function a(a) {
var a = function() {};
return [ arguments[0], a ];
})(42).forEach(function(b) {
console.log(typeof b);
});
}
expect: {
(function(a) {
a = function() {};
return [ arguments[0], a ];
})(42).forEach(function(b) {
console.log(typeof b);
});
}
expect_stdout: [
"function",
"function",
]
}

View File

@@ -3117,3 +3117,28 @@ issue_4422: {
}
expect_stdout: "PASS"
}
issue_4480: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
var a = function f(b) {
b = "FAIL";
arguments[0] = "PASS";
var arguments = 0;
console.log(b);
}(a);
}
expect: {
var a = function(b) {
b = "FAIL";
arguments[0] = "PASS";
var arguments = 0;
console.log(b);
}(a);
}
expect_stdout: "PASS"
}

View File

@@ -229,7 +229,7 @@ issue_203: {
}
expect: {
var m = {};
var fn = Function("n,o", "o.exports=42");
var fn = Function("n,o,t", "o.exports=42");
fn(null, m, m.exports);
console.log(m.exports);
}
@@ -4230,7 +4230,7 @@ substitute: {
substitute_add_farg: {
options = {
inline: true,
keep_fargs: "strict",
keep_fargs: false,
}
input: {
function f(g) {
@@ -4411,7 +4411,9 @@ substitute_drop_farg: {
return f;
},
function() {
return f;
return function(d, e) {
return f(d, e);
};
},
].forEach(function(g) {
console.log(g()(o), g().call(o, o));
@@ -4594,7 +4596,7 @@ substitute_use_strict: {
issue_3833: {
options = {
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -4751,7 +4753,7 @@ issue_4006: {
dead_code: true,
evaluate: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -5132,8 +5134,8 @@ issue_4259: {
console.log(typeof a);
}
expect: {
function a() {
for (a in a);
var a = function b() {
for (b in b);
}
a();
console.log(typeof a);
@@ -5223,3 +5225,61 @@ trailing_comma: {
expect_exact: 'new function(a,b){console.log(b,a)}(42,"PASS");'
expect_stdout: "PASS 42"
}
issue_4451: {
options = {
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = function f() {
for (f in "foo")
return f;
};
while (console.log(typeof a()));
}
expect: {
var a = function f() {
for (f in "foo")
return f;
};
while (console.log(typeof a()));
}
expect_stdout: "function"
}
issue_4471: {
options = {
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
f(f());
function f() {
return g();
}
function g() {
{
console.log("PASS");
}
}
}
expect: {
f(g());
function f() {
return g();
}
function g() {
console.log("PASS");
}
}
expect_stdout: [
"PASS",
"PASS",
]
}

View File

@@ -89,6 +89,31 @@ sequences_funs: {
}
}
catch_var: {
options = {
dead_code: true,
hoist_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
try {
a;
} catch (a) {
var a = 0;
a;
}
console.log(a);
}
expect: {
var a = "PASS";
console.log(a);
}
expect_stdout: "PASS"
}
issue_2295: {
options = {
collapse_vars: true,

View File

@@ -63,42 +63,81 @@ eval_unused: {
unused: true,
}
input: {
function f1(a, eval, c, d, e) {
return a('c') + eval;
}
function f2(a, b, c, d, e) {
return a + eval('c');
}
function f3(a, eval, c, d, e) {
return a + eval('c');
function o(k) {
return { c: 14 }[k];
}
console.log(function f1(a, eval, c, d, e) {
return a("c") + eval;
}(o, 28, true));
console.log(function f2(a, b, c, d, e) {
return a + eval("c");
}(14, true, 28));
console.log(function f3(a, eval, c, d, e) {
return a + eval("c");
}(28, o, true));
}
expect: {
function f1(a, eval) {
return a('c') + eval;
}
function f2(a, b, c, d, e) {
return a + eval('c');
}
function f3(a, eval, c, d, e) {
return a + eval('c');
function o(k) {
return { c: 14 }[k];
}
console.log(function(a, eval) {
return a("c") + eval;
}(o, 28));
console.log(function f2(a, b, c, d, e) {
return a + eval("c");
}(14, true, 28));
console.log(function f3(a, eval, c, d, e) {
return a + eval("c");
}(28, o, true));
}
expect_stdout: [
"42",
"42",
"42",
]
}
eval_mangle: {
mangle = {
};
input: {
function f1(a, eval, c, d, e) {
return a('c') + eval;
}
function f2(a, b, c, d, e) {
return a + eval('c');
}
function f3(a, eval, c, d, e) {
return a + eval('c');
}
mangle = {}
beautify = {
beautify: true,
}
expect_exact: 'function f1(n,c,e,a,f){return n("c")+c}function f2(a,b,c,d,e){return a+eval("c")}function f3(a,eval,c,d,e){return a+eval("c")}'
input: {
function o(k) {
return { cc: 14 }[k + "c"];
}
console.log(function f1(a, eval, c, d, e) {
return a("c") + eval;
}(o, 28, true));
console.log(function f2(a, b, c, d, e) {
return a + eval("c");
}(14, true, 28));
console.log(function f3(a, eval, c, d, e) {
return a + eval("c");
}(28, o, true));
}
expect_exact: [
"function o(o) {",
" return {",
" cc: 14",
' }[o + "c"];',
"}",
"",
"console.log(function o(c, e, n, r, t) {",
' return c("c") + e;',
"}(o, 28, true));",
"",
"console.log(function f2(a, b, c, d, e) {",
' return a + eval("c");',
"}(14, true, 28));",
"",
"console.log(function f3(a, eval, c, d, e) {",
' return a + eval("c");',
"}(28, o, true));",
]
expect_stdout: [
"42",
"42",
"42",
]
}

View File

@@ -790,7 +790,7 @@ issue_3795: {
dead_code: true,
evaluate: true,
join_vars: true,
keep_fargs: "strict",
keep_fargs: false,
loops: true,
passes: 2,
reduce_vars: true,

View File

@@ -18,43 +18,6 @@ keep_fargs_false: {
function j(e) {}
console.log(h(), i().length, j.length);
}
expect: {
console.log(function f() {
return f.length;
}(), function g() {
return g;
}().length);
function h() {
return h.length;
}
function i() {
return i;
}
function j() {}
console.log(h(), i().length, j.length);
}
}
keep_fargs_strict: {
options = {
keep_fargs: "strict",
unused: true,
}
input: {
console.log(function f(a) {
return f.length;
}(), function g(b) {
return g;
}().length);
function h(c) {
return h.length;
}
function i(d) {
return i;
}
function j(e) {}
console.log(h(), i().length, j.length);
}
expect: {
console.log(function f(a) {
return f.length;
@@ -117,61 +80,11 @@ keep_fargs_true: {
]
}
replace_index: {
options = {
arguments: true,
evaluate: true,
keep_fargs: "strict",
properties: true,
}
input: {
var arguments = [];
console.log(arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
var arguments = [];
console.log(arguments[0]);
(function(argument_0, argument_1) {
console.log(argument_1, argument_1, arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
replace_index_strict: {
options = {
arguments: true,
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
properties: true,
reduce_vars: true,
}
@@ -202,7 +115,7 @@ replace_index_strict: {
issue_1858: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
pure_getters: true,
unused: true,
}
@@ -224,7 +137,7 @@ issue_1858: {
issue_2187_2: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -245,7 +158,7 @@ issue_2187_2: {
issue_2203_2: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -280,7 +193,7 @@ issue_2203_2: {
issue_2298: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
@@ -323,7 +236,7 @@ issue_2298: {
issue_2319_1: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -346,7 +259,7 @@ issue_2319_1: {
issue_2319_2: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -371,7 +284,7 @@ issue_2319_2: {
issue_2319_3: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -396,7 +309,7 @@ issue_2319_3: {
issue_2425_1: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -419,7 +332,7 @@ issue_2425_1: {
issue_2425_2: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -442,7 +355,7 @@ issue_2425_2: {
issue_2425_3: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -465,7 +378,7 @@ issue_2425_3: {
issue_2436_13: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_vars: true,
unused: true,
@@ -499,7 +412,7 @@ issue_2436_13: {
issue_2506: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_vars: true,
unused: true,
@@ -538,7 +451,7 @@ issue_2506: {
issue_2226_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
side_effects: true,
unused: true,
}
@@ -585,7 +498,7 @@ issue_2226_1: {
issue_2226_2: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
sequences: true,
side_effects: true,
unused: true,
@@ -607,7 +520,7 @@ issue_2226_2: {
issue_2226_3: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
side_effects: true,
unused: true,
}
@@ -627,7 +540,7 @@ issue_2226_3: {
issue_3192: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -657,7 +570,7 @@ issue_3192: {
if_increment: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -679,7 +592,7 @@ if_increment: {
try_increment: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -703,7 +616,7 @@ try_increment: {
issue_2630_3: {
options = {
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -740,7 +653,7 @@ issue_2630_3: {
issue_3364: {
options = {
functions: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
toplevel: true,
unused: true,
@@ -805,7 +718,7 @@ issue_3364: {
defun_label: {
options = {
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
@@ -837,7 +750,7 @@ defun_label: {
iife_func_side_effects: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
@@ -889,7 +802,7 @@ iife_func_side_effects: {
issue_1595_1: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
@@ -909,7 +822,7 @@ issue_1595_1: {
issue_1595_2: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
@@ -929,7 +842,7 @@ issue_1595_2: {
issue_1595_3: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
@@ -950,7 +863,7 @@ issue_1595_3: {
issue_1595_4: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_funcs: true,
reduce_vars: true,
unused: true,
@@ -972,7 +885,7 @@ issue_1595_4: {
duplicate_lambda_defun_name_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
}
input: {
@@ -992,7 +905,7 @@ duplicate_lambda_defun_name_1: {
duplicate_lambda_defun_name_2: {
options = {
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_vars: true,
unused: true,
@@ -1013,7 +926,7 @@ duplicate_lambda_defun_name_2: {
function_name_mangle: {
options = {
keep_fargs: "strict",
keep_fargs: false,
keep_fnames: true,
reduce_vars: true,
unused: true,
@@ -1031,7 +944,7 @@ function_name_mangle: {
function_name_mangle_ie8: {
options = {
keep_fargs: "strict",
keep_fargs: false,
keep_fnames: true,
reduce_vars: true,
unused: true,
@@ -1052,7 +965,7 @@ function_name_mangle_ie8: {
issue_3420_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1075,7 +988,7 @@ issue_3420_1: {
issue_3420_2: {
options = {
inline: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1096,7 +1009,7 @@ issue_3420_2: {
issue_3420_3: {
options = {
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -1118,7 +1031,7 @@ issue_3420_3: {
issue_3423_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1138,7 +1051,7 @@ issue_3423_1: {
issue_3423_2: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1165,7 +1078,7 @@ collapse_vars_repeated: {
hoist_funs: true,
if_return: true,
join_vars: true,
keep_fargs: "strict",
keep_fargs: false,
loops: true,
properties: true,
reduce_funcs: true,
@@ -1212,7 +1125,7 @@ collapse_vars_repeated: {
chained_3: {
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1236,7 +1149,7 @@ replace_all_var_scope: {
rename = true
options = {
collapse_vars: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
mangle = {}
@@ -1265,7 +1178,7 @@ replace_all_var_scope: {
issue_1583: {
options = {
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
@@ -1302,7 +1215,7 @@ issues_3267_1: {
dead_code: true,
evaluate: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -1331,7 +1244,7 @@ issues_3267_1: {
trailing_argument_side_effects: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -1355,7 +1268,7 @@ trailing_argument_side_effects: {
recursive_iife_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -1374,7 +1287,7 @@ recursive_iife_1: {
recursive_iife_2: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -1455,7 +1368,7 @@ issue_3619: {
issue_4353_1: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}
@@ -1470,7 +1383,7 @@ issue_4353_1: {
issue_4353_2: {
options = {
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
unused: true,
}

View File

@@ -207,3 +207,123 @@ labels_10: {
}
}
}
issue_4466_1: {
mangle = {
v8: false,
}
input: {
A: if (console.log("PASS"))
B:;
else
C:;
}
expect: {
e: if (console.log("PASS"))
l:;
else
l:;
}
expect_stdout: "PASS"
node_version: ">=12"
}
issue_4466_1_v8: {
mangle = {
v8: true,
}
input: {
A: if (console.log("PASS"))
B:;
else
C:;
}
expect: {
e: if (console.log("PASS"))
l:;
else
o:;
}
expect_stdout: "PASS"
node_version: ">=12"
}
issue_4466_2: {
mangle = {
toplevel: false,
v8: false,
}
input: {
if (console.log("PASS"))
A:;
else
B:;
}
expect: {
if (console.log("PASS"))
e:;
else
e:;
}
expect_stdout: "PASS"
}
issue_4466_2_v8: {
mangle = {
toplevel: false,
v8: true,
}
input: {
if (console.log("PASS"))
A:;
else
B:;
}
expect: {
if (console.log("PASS"))
e:;
else
l:;
}
expect_stdout: "PASS"
}
issue_4466_2_toplevel: {
mangle = {
toplevel: true,
v8: false,
}
input: {
if (console.log("PASS"))
A:;
else
B:;
}
expect: {
if (console.log("PASS"))
e:;
else
e:;
}
expect_stdout: "PASS"
}
issue_4466_2_toplevel_v8: {
mangle = {
toplevel: true,
v8: true,
}
input: {
if (console.log("PASS"))
A:;
else
B:;
}
expect: {
if (console.log("PASS"))
e:;
else
e:;
}
expect_stdout: "PASS"
}

View File

@@ -359,6 +359,28 @@ reduce_block_2_toplevel: {
node_version: ">=4"
}
reduce_vars: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
let a = "PASS";
console.log(a);
a = "FAIL";
}
expect: {
"use strict";
console.log("PASS");
"FAIL";
}
expect_stdout: "PASS"
node_version: ">=4"
}
hoist_props: {
options = {
hoist_props: true,
@@ -1228,3 +1250,35 @@ issue_1753_toplevel: {
expect_stdout: "0"
node_version: ">=4"
}
issue_4438: {
options = {
if_return: true,
}
input: {
"use strict";
function f() {
if (console) {
{
let a = console.log;
return void a("PASS");
}
}
}
f();
}
expect: {
"use strict";
function f() {
if (!console)
;
else {
let a = console.log;
a("PASS");
}
}
f();
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -1026,7 +1026,7 @@ issue_4075: {
issue_4082: {
options = {
keep_fargs: "strict",
keep_fargs: false,
loops: true,
unused: true,
}
@@ -1050,7 +1050,7 @@ issue_4082: {
issue_4084: {
options = {
keep_fargs: "strict",
keep_fargs: false,
loops: true,
passes: 2,
reduce_vars: true,

View File

@@ -327,7 +327,7 @@ issue_4103: {
issue_4107: {
options = {
keep_fargs: "strict",
keep_fargs: false,
merge_vars: true,
reduce_vars: true,
unused: true,

View File

@@ -685,7 +685,7 @@ issue_3858: {
options = {
collapse_vars: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {
@@ -711,7 +711,7 @@ inline_pure_call_1: {
options = {
collapse_vars: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -733,7 +733,7 @@ inline_pure_call_2: {
options = {
collapse_vars: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
sequences: true,
side_effects: true,
@@ -756,7 +756,7 @@ inline_pure_call_3: {
collapse_vars: true,
evaluate: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
reduce_vars: true,
toplevel: true,

View File

@@ -1208,3 +1208,32 @@ issue_3427: {
expect: {}
expect_stdout: true
}
issue_4440: {
options = {
pure_getters: "strict",
side_effects: true,
unused: true,
}
input: {
try {
(function() {
arguments = null;
console.log(arguments.p = "FAIL");
})();
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
(function() {
arguments = null;
console.log(arguments.p = "FAIL");
})();
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}

View File

@@ -2373,7 +2373,7 @@ redefine_farg_1: {
function f(a) {
return typeof a;
}
function g() {
function g(a) {
return "number";
}
function h(a, b) {
@@ -6928,7 +6928,7 @@ issue_3622: {
options = {
evaluate: true,
inline: true,
keep_fargs: "strict",
keep_fargs: false,
reduce_vars: true,
sequences: true,
toplevel: true,
@@ -7196,7 +7196,7 @@ issue_3894: {
issue_3922: {
options = {
evaluate: true,
keep_fargs: "strict",
keep_fargs: false,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,

View File

@@ -436,7 +436,7 @@ trim_new: {
issue_4325: {
options = {
keep_fargs: "strict",
keep_fargs: false,
passes: 2,
pure_getters: "strict",
reduce_vars: true,

View File

@@ -192,7 +192,7 @@ keep_property_access: {
keep_fargs: {
options = {
keep_fargs: "strict",
keep_fargs: false,
unused: true,
}
input: {

View File

@@ -1,5 +1,5 @@
(function f(a) {
do {
console.log(f.length);
} while (console.log(f += 0));
})();
console.log(function(undefined) {
return undefined[function() {
{}
}] || 1 + .1 + .1;
}(42));

View File

@@ -1,19 +1,14 @@
// (beautified)
(function f(a) {
do {
console.log(f.length);
} while (console.log(f += 0));
})();
// output: 1
// function(){}0
console.log(function() {
return 1 + .1 + .1;
}());
// output: 1.2000000000000002
//
// minify: 0
// function(){}0
// minify: 1.2
//
// options: {
// "compress": {
// "keep_fargs": false,
// "unsafe": true
// "unsafe_math": true
// },
// "mangle": false
// }

View File

@@ -1,8 +1,5 @@
console.log(function f(a) {
({
set p(v) {
f++;
}
});
return f.length;
}());
({
set p(v) {
console.log(+v + .1 + .1);
}
}).p = 1;

View File

@@ -1,20 +1,16 @@
// (beautified)
console.log(function f(a) {
({
set p(v) {
f++;
}
});
return f.length;
}());
// output: 1
({
set p(v) {
console.log(1 + .1 + .1);
}
}).p = 0;
// output: 1.2000000000000002
//
// minify: 0
// minify: 1.2
//
// options: {
// "compress": {
// "keep_fargs": false,
// "unsafe": true
// "unsafe_math": true
// },
// "mangle": false
// }

View File

@@ -5,7 +5,7 @@
var site = "https://browserbench.org/JetStream1.1";
if (typeof phantom == "undefined") {
require("../tools/exit");
require("../tools/tty");
var args = process.argv.slice(2);
var debug = args.indexOf("--debug");
if (debug < 0) {

View File

@@ -3,7 +3,7 @@ var UglifyJS = require("../node");
describe("Getters and setters", function() {
it("Should not accept operator symbols as getter/setter name", function() {
var illegalOperators = [
[
"++",
"--",
"+",
@@ -42,43 +42,26 @@ describe("Getters and setters", function() {
"&=",
"&&",
"||"
];
var generator = function() {
var results = [];
for (var i in illegalOperators) {
results.push({
code: "var obj = { get " + illegalOperators[i] + "() { return test; }};",
operator: illegalOperators[i],
method: "get"
});
results.push({
code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};",
operator: illegalOperators[i],
method: "set"
});
}
return results;
};
var testCase = function(data) {
return function() {
UglifyJS.parse(data.code);
};
};
var fail = function(data) {
return function(e) {
].reduce(function(tests, illegalOperator) {
tests.push({
code: "var obj = { get " + illegalOperator + "() { return test; }};",
operator: illegalOperator,
});
tests.push({
code: "var obj = { set " + illegalOperator + "(value) { test = value; }};",
operator: illegalOperator,
});
return tests;
}, []).forEach(function(test) {
assert.throws(function() {
UglifyJS.parse(test.code);
}, test.operator == "=" ? function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Unexpected token: operator «" + data.operator + "»";
};
};
var errorMessage = function(data) {
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
};
var tests = generator();
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
assert.throws(testCase(test), fail(test), errorMessage(test));
}
&& /^Unexpected token: punc «{», expected: punc «.*?»$/.test(e.message);
} : function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Unexpected token: operator «" + test.operator + "»";
}, "Expected but didn't get a syntax error while parsing following line:\n" + test.code);
});
});
});

View File

@@ -89,4 +89,13 @@ describe("Number literals", function() {
}, code);
});
});
it("Should reject invalid syntax under expression=true", function() {
assert.throws(function() {
UglifyJS.parse("42.g", {
expression: true,
});
}, function(e) {
return e instanceof UglifyJS.JS_Parse_Error;
});
});
});

View File

@@ -37,8 +37,7 @@ describe("test/reduce.js", function() {
it("Should retain setter arguments", function() {
var result = reduce_test(read("test/input/reduce/setter.js"), {
compress: {
keep_fargs: false,
unsafe: true,
unsafe_math: true,
},
mangle: false,
}, {
@@ -110,28 +109,24 @@ describe("test/reduce.js", function() {
});
it("Should print correct output for irreducible test case", function() {
var result = reduce_test([
"console.log(function f(a) {",
" return f.length;",
"}());",
"console.log(1 + .1 + .1);",
].join("\n"), {
compress: {
keep_fargs: false,
unsafe_math: true,
},
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"// (beautified)",
"console.log(function f(a) {",
" return f.length;",
"}());",
"// output: 1",
"console.log(1 + .1 + .1);",
"// output: 1.2000000000000002",
"// ",
"// minify: 0",
"// minify: 1.2",
"// ",
"// options: {",
'// "compress": {',
'// "keep_fargs": false',
'// "unsafe_math": true',
"// },",
'// "mangle": false',
"// }",
@@ -303,8 +298,7 @@ describe("test/reduce.js", function() {
if (semver.satisfies(process.version, "<=0.10")) return;
var result = reduce_test(read("test/input/reduce/diff_error.js"), {
compress: {
keep_fargs: false,
unsafe: true,
unsafe_math: true,
},
mangle: false,
}, {

View File

@@ -124,7 +124,6 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
// ignore lvalues
if (parent instanceof U.AST_Assign && parent.left === node) return;
if (parent instanceof U.AST_DestructuredArray) return;
if (parent instanceof U.AST_DestructuredKeyVal && parent.value === node) return;
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
case "++":
@@ -153,6 +152,20 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
node.left,
node.right,
][ permute & 1 ];
if (expr instanceof U.AST_Destructured) expr = expr.transform(new U.TreeTransformer(function(node, descend) {
if (node instanceof U.AST_DefaultValue) return new U.AST_Assign({
operator: "=",
left: node.name.transform(this),
right: node.value,
start: {},
});
if (node instanceof U.AST_DestructuredKeyVal) return new U.AST_ObjectKeyVal(node);
if (node instanceof U.AST_Destructured) {
node = new (node instanceof U.AST_DestructuredArray ? U.AST_Array : U.AST_Object)(node);
descend(node, this);
}
return node;
}));
CHANGED = true;
return permute < 2 ? expr : wrap_with_console_log(expr);
}
@@ -211,6 +224,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
node.alternative,
][ ((node.start._permute += step) * steps | 0) % 3 ];
}
else if (node instanceof U.AST_DefaultValue) {
node.start._permute++;
CHANGED = true;
return node.name;
}
else if (node instanceof U.AST_Defun) {
switch (((node.start._permute += step) * steps | 0) % 2) {
case 0:
@@ -333,6 +351,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
}
}
}
else if (node instanceof U.AST_Spread) {
node.start._permute++;
CHANGED = true;
return node.expression;
}
else if (node instanceof U.AST_Switch) {
var expr = [
node.expression, // switch expression

View File

@@ -64,7 +64,7 @@ function createContext() {
}
}
exports.run_code = function(code, toplevel, timeout) {
function run_code(code, toplevel, timeout) {
timeout = timeout || 5000;
var stdout = "";
var original_write = process.stdout.write;
@@ -79,7 +79,17 @@ exports.run_code = function(code, toplevel, timeout) {
} finally {
process.stdout.write = original_write;
}
};
}
exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, toplevel, timeout) {
var stdout = run_code(code, toplevel, timeout);
if (typeof stdout != "string" || !/arguments/.test(code)) return stdout;
do {
var prev = stdout;
stdout = run_code(code, toplevel, timeout);
} while (prev !== stdout);
return stdout;
} : run_code;
function strip_func_ids(text) {
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");

View File

@@ -5,7 +5,7 @@
// bin/uglifyjs s.js -c && bin/uglifyjs s.js -c passes=3 && bin/uglifyjs s.js -c passes=3 -m
// cat s.js | node && node s.js && bin/uglifyjs s.js -c | node && bin/uglifyjs s.js -c passes=3 | node && bin/uglifyjs s.js -c passes=3 -m | node
require("../../tools/exit");
require("../../tools/tty");
var UglifyJS = require("../..");
var randomBytes = require("crypto").randomBytes;
@@ -137,6 +137,7 @@ var SUPPORT = function(matrix) {
catch_omit_var: "try {} catch {}",
computed_key: "({[0]: 0});",
const_block: "var a; { const a = 0; }",
default_value: "[ a = 0 ] = [];",
destructuring: "[] = [];",
let: "let a;",
spread: "[...[]];",
@@ -425,18 +426,35 @@ function createArgs(recurmax, stmtDepth, canThrow) {
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async) {
var avoid = [];
var len = unique_vars.length;
var pairs = createPairs(recurmax);
var pairs = createPairs(recurmax, !nameLenBefore);
unique_vars.length = len;
return pairs;
function createAssignmentValue(recurmax) {
function fill(nameFn, valueFn) {
var save_async = async;
if (was_async != null) async = was_async;
if (was_async != null) {
async = false;
if (save_async || was_async) addAvoidVar("await");
}
avoid.forEach(addAvoidVar);
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
var value = nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
if (nameFn) nameFn();
if (was_async != null) {
async = was_async;
if (save_async || was_async) removeAvoidVar("await");
}
if (valueFn) valueFn();
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
avoid.forEach(removeAvoidVar);
async = save_async;
return value;
}
function createAssignmentValue(recurmax) {
return nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
}
function createDefaultValue(recurmax, noDefault) {
return !noDefault && SUPPORT.default_value && rng(20) == 0 ? " = " + createAssignmentValue(recurmax) : "";
}
function createKey(recurmax, keys) {
@@ -459,20 +477,22 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
return name;
}
function createPairs(recurmax) {
function createPairs(recurmax, noDefault) {
var names = [], values = [];
var m = rng(4), n = rng(4);
if (!nameLenBefore) m = Math.max(m, n, 1);
for (var i = Math.max(m, n); --i >= 0;) {
if (i < m && i < n) {
createDestructured(recurmax, names, values);
continue;
}
if (i < m) {
names.unshift(createName());
}
if (i < n) {
values.unshift(createAssignmentValue(recurmax));
createDestructured(recurmax, noDefault, names, values);
} else if (i < m) {
var name = createName();
fill(function() {
names.unshift(name + createDefaultValue(recurmax, noDefault));
});
} else {
fill(null, function() {
values.unshift(createAssignmentValue(recurmax));
});
}
}
return {
@@ -481,7 +501,7 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
};
}
function createDestructured(recurmax, names, values) {
function createDestructured(recurmax, noDefault, names, values) {
switch (rng(20)) {
case 0:
if (--recurmax < 0) {
@@ -489,20 +509,25 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
values.unshift('""');
} else {
var pairs = createPairs(recurmax);
while (!rng(10)) {
var index = rng(pairs.names.length + 1);
pairs.names.splice(index, 0, "");
if (index < pairs.values.length) {
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
} else switch (rng(5)) {
case 0:
pairs.values[index] = createAssignmentValue(recurmax);
case 1:
pairs.values.length = index + 1;
var default_value;
fill(function() {
default_value = createDefaultValue(recurmax, noDefault);
}, function() {
while (!rng(10)) {
var index = rng(pairs.names.length + 1);
pairs.names.splice(index, 0, "");
if (index < pairs.values.length) {
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
} else switch (rng(5)) {
case 0:
pairs.values[index] = createAssignmentValue(recurmax);
case 1:
pairs.values.length = index + 1;
}
}
}
names.unshift("[ " + pairs.names.join(", ") + " ]");
values.unshift("[ " + pairs.values.join(", ") + " ]");
names.unshift("[ " + pairs.names.join(", ") + " ]" + default_value);
values.unshift("[ " + pairs.values.join(", ") + " ]");
});
}
break;
case 1:
@@ -521,33 +546,26 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
keys[index] = key;
}
});
var save_async = async;
if (was_async != null) {
async = false;
if (save_async || was_async) avoid.push("await");
}
addAvoidVars(avoid);
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
names.unshift("{ " + addTrailingComma(pairs.names.map(function(name, index) {
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
return key ? key + ": " + name : name;
}).join(", ")) + " }");
if (was_async != null) {
async = was_async;
if (save_async || was_async) removeAvoidVars([ avoid.pop() ]);
}
values.unshift("{ " + addTrailingComma(pairs.values.map(function(value, index) {
var key = index in keys ? keys[index] : createKey(recurmax, keys);
return key + ": " + value;
}).join(", ")) + " }");
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
removeAvoidVars(avoid);
async = save_async;
fill(function() {
names.unshift("{ " + addTrailingComma(pairs.names.map(function(name, index) {
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
return key ? key + ": " + name : name;
}).join(", ")) + " }" + createDefaultValue(recurmax, noDefault));
}, function() {
values.unshift("{ " + addTrailingComma(pairs.values.map(function(value, index) {
var key = index in keys ? keys[index] : createKey(recurmax, keys);
return key + ": " + value;
}).join(", ")) + " }");
});
}
break;
default:
names.unshift(createName());
values.unshift(createAssignmentValue(recurmax));
var name = createName();
fill(function() {
names.unshift(name + createDefaultValue(recurmax, noDefault));
}, function() {
values.unshift(createAssignmentValue(recurmax));
});
break;
}
}
@@ -575,8 +593,8 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
}
unique_vars.length -= 6;
fn(function() {
addAvoidVars(consts);
addAvoidVars(lets);
consts.forEach(addAvoidVar);
lets.forEach(addAvoidVar);
if (rng(2)) {
return createDefinitions("const", consts) + "\n" + createDefinitions("let", lets) + "\n";
} else {
@@ -610,17 +628,17 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
default:
s += names.map(function(name) {
if (type == "let" && !rng(10)) {
removeAvoidVars([ name ]);
removeAvoidVar(name);
return name;
}
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
removeAvoidVars([ name ]);
removeAvoidVar(name);
return name + " = " + value;
}).join(", ") + ";";
names.length = 0;
break;
}
removeAvoidVars(names);
names.forEach(removeAvoidVar);
return s;
}
}
@@ -877,9 +895,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
unique_vars.length -= 6;
if (SUPPORT.computed_key && rng(10) == 0) {
s += " catch ({ message: " + message + ", ";
addAvoidVars([ name ]);
addAvoidVar(name);
s += "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]: " + name;
removeAvoidVars([ name ]);
removeAvoidVar(name);
s += " }) { ";
} else {
s += " catch ({ name: " + name + ", message: " + message + " }) { ";
@@ -1483,15 +1501,13 @@ function createUnaryPostfix() {
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
}
function addAvoidVars(names) {
avoid_vars = avoid_vars.concat(names);
function addAvoidVar(name) {
avoid_vars.push(name);
}
function removeAvoidVars(names) {
names.forEach(function(name) {
var index = avoid_vars.lastIndexOf(name);
if (index >= 0) avoid_vars.splice(index, 1);
});
function removeAvoidVar(name) {
var index = avoid_vars.lastIndexOf(name);
if (index >= 0) avoid_vars.splice(index, 1);
}
function getVarName(noConst) {
@@ -1664,18 +1680,20 @@ function log(options) {
}
}
errorln("//-------------------------------------------------------------");
var reduce_options = JSON.parse(options);
reduce_options.validate = true;
var reduced = reduce_test(original_code, reduce_options, {
verbose: false,
}).code;
if (reduced) {
errorln();
errorln("// reduced test case (output will differ)");
errorln();
errorln(reduced);
errorln();
errorln("//-------------------------------------------------------------");
if (!ok) {
var reduce_options = JSON.parse(options);
reduce_options.validate = true;
var reduced = reduce_test(original_code, reduce_options, {
verbose: false,
}).code;
if (reduced) {
errorln();
errorln("// reduced test case (output will differ)");
errorln();
errorln(reduced);
errorln();
errorln("//-------------------------------------------------------------");
}
}
errorln("minify(options):");
errorln(JSON.stringify(JSON.parse(options), null, 2));
@@ -1692,7 +1710,9 @@ function log(options) {
function sort_globals(code) {
var globals = sandbox.run_code("throw Object.keys(this).sort();" + code);
return globals.length ? "var " + globals.join(",") + ";" + code : code;
return globals.length ? "var " + globals.map(function(name) {
return name + "=" + name;
}).join(",") + ";" + code : code;
}
function fuzzy_match(original, uglified) {
@@ -1781,6 +1801,12 @@ var beautify_options = {
},
};
var minify_options = require("./options.json");
if (typeof sandbox.run_code("A:if (0) B:; else B:;") != "string") {
minify_options.forEach(function(o) {
if (!("mangle" in o)) o.mangle = {};
if (o.mangle) o.mangle.v8 = true;
});
}
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
beautify_options.output.v8 = true;
minify_options.forEach(function(o) {
@@ -1799,6 +1825,8 @@ for (var round = 1; round <= num_iterations; round++) {
var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ];
errored = typeof orig_result[0] != "string";
if (errored) {
println();
println();
println("//=============================================================");
println("// original code");
try_beautify(original_code, false, orig_result[0], println);

View File

@@ -70,7 +70,7 @@ function run() {
function trap(data) {
stderr += data;
if (~stderr.indexOf("\nminify(options):\n")) {
if (~stderr.indexOf("!!!!!! Failed... round ")) {
process.exitCode = 1;
child.stderr.removeListener("data", trap);
}

View File

@@ -21,14 +21,16 @@
},
{
"compress": {
"hoist_vars": true,
"keep_infinity": true,
"passes": 1e6,
"unsafe": true
},
"keep_fnames": true,
"toplevel": true
},
{
"compress": {
"keep_fargs": false,
"passes": 1e6,
"sequences": 1e6,
"unsafe": true,

View File

@@ -1,15 +0,0 @@
// workaround for tty output truncation upon process.exit()
var exit = process.exit;
process.exit = function() {
var args = [].slice.call(arguments);
process.once("uncaughtException", function() {
(function callback() {
if (process.stdout.bufferSize || process.stderr.bufferSize) {
setTimeout(callback, 1);
} else {
exit.apply(process, args);
}
})();
});
throw exit;
};

22
tools/tty.js Normal file
View File

@@ -0,0 +1,22 @@
// workaround for tty output truncation on Node.js
try {
// prevent buffer overflow and other asynchronous bugs
process.stdout._handle.setBlocking(true);
process.stderr._handle.setBlocking(true);
} catch (e) {
// ensure output buffers are flushed before process termination
var exit = process.exit;
process.exit = function() {
var args = [].slice.call(arguments);
process.once("uncaughtException", function() {
(function callback() {
if (process.stdout.bufferSize || process.stderr.bufferSize) {
setTimeout(callback, 1);
} else {
exit.apply(process, args);
}
})();
});
throw exit;
};
}