Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77261e1ee0 | ||
|
|
903a5df9a5 | ||
|
|
c810ecd081 | ||
|
|
dce9dfce0e | ||
|
|
3d72663689 | ||
|
|
a2b16e89a4 | ||
|
|
b35f4c5a83 | ||
|
|
41eb4f1725 | ||
|
|
94bc221669 | ||
|
|
822d298a55 | ||
|
|
273c6020ba | ||
|
|
1b07f64057 | ||
|
|
80d9c44b22 | ||
|
|
dc0cd088cf | ||
|
|
c69c026728 | ||
|
|
b5f4e1187f | ||
|
|
827bcec186 | ||
|
|
d105ab9722 | ||
|
|
b39228892d | ||
|
|
ff72eaa3c3 | ||
|
|
0a1c9b34ce | ||
|
|
03e968be62 | ||
|
|
421bb7083a | ||
|
|
bdc8ef2218 | ||
|
|
bca52fcba2 | ||
|
|
d6d31cbb5a | ||
|
|
a051846d22 | ||
|
|
3485472866 | ||
|
|
c8d60d6983 | ||
|
|
6092bf23de | ||
|
|
7052ce5aef | ||
|
|
d13b71297e | ||
|
|
457f958af3 | ||
|
|
53517db3e4 | ||
|
|
c13caf4876 | ||
|
|
fbfa6178a6 | ||
|
|
5315dd95b0 | ||
|
|
31a7bf2a22 | ||
|
|
f0a29902ac | ||
|
|
0d820e4c0a | ||
|
|
f01f580d6c | ||
|
|
c01ff76288 | ||
|
|
83a42716c3 | ||
|
|
2557148bba | ||
|
|
dd22eda888 | ||
|
|
f4c77886e7 | ||
|
|
df547ffd97 | ||
|
|
70551febc8 | ||
|
|
44499a6643 | ||
|
|
470a7d4df1 | ||
|
|
551420132c | ||
|
|
b0040ba654 | ||
|
|
c93ca6ee53 | ||
|
|
df506439b1 |
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -4,10 +4,10 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
node: [ "0.10", "0.12", "4", "6", "8", "10", latest ]
|
||||||
os: [ ubuntu-latest, windows-latest ]
|
os: [ ubuntu-latest, windows-latest ]
|
||||||
node: [ "0.10", 0.12, 4, 6, 8, 10, latest ]
|
|
||||||
script: [ compress, mocha, release/benchmark, release/jetstream ]
|
script: [ compress, mocha, release/benchmark, release/jetstream ]
|
||||||
name: ${{ matrix.os }} ${{ matrix.node }} ${{ matrix.script }}
|
name: ${{ matrix.node }} ${{ matrix.os }} ${{ matrix.script }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
env:
|
env:
|
||||||
NODE: ${{ matrix.node }}
|
NODE: ${{ matrix.node }}
|
||||||
@@ -21,11 +21,19 @@ jobs:
|
|||||||
- name: Perform tests
|
- name: Perform tests
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
git clone --branch v1.5.3 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
git clone --branch v1.5.4 --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
|
||||||
|
git clean -xdf
|
||||||
|
cd -
|
||||||
|
done
|
||||||
. ~/.nvs/nvs.sh --version
|
. ~/.nvs/nvs.sh --version
|
||||||
nvs add $NODE
|
|
||||||
nvs use $NODE
|
nvs use $NODE
|
||||||
node --version
|
node --version
|
||||||
npm --version --no-update-notifier
|
npm config set audit false
|
||||||
npm install --no-audit --no-optional --no-save --no-update-notifier
|
npm config set optional false
|
||||||
|
npm config set save false
|
||||||
|
npm config set update-notifier false
|
||||||
|
npm --version
|
||||||
|
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||||
node test/$TYPE
|
node test/$TYPE
|
||||||
|
|||||||
16
.github/workflows/ufuzz.yml
vendored
16
.github/workflows/ufuzz.yml
vendored
@@ -15,11 +15,19 @@ jobs:
|
|||||||
- name: Perform fuzzing
|
- name: Perform fuzzing
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
git clone --branch v1.5.3 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||||
|
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 10 && nvs use 10'; do
|
||||||
|
cd ~/.nvs
|
||||||
|
git clean -xdf
|
||||||
|
cd -
|
||||||
|
done
|
||||||
. ~/.nvs/nvs.sh --version
|
. ~/.nvs/nvs.sh --version
|
||||||
nvs add 10
|
|
||||||
nvs use 10
|
nvs use 10
|
||||||
node --version
|
node --version
|
||||||
npm --version --no-update-notifier
|
npm config set audit false
|
||||||
npm install --no-audit --no-optional --no-save --no-update-notifier
|
npm config set optional false
|
||||||
|
npm config set save false
|
||||||
|
npm config set update-notifier false
|
||||||
|
npm --version
|
||||||
|
while !(npm install); do echo "'npm install' failed - retrying..."; done
|
||||||
node test/ufuzz/job 3600000
|
node test/ufuzz/job 3600000
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -848,8 +848,14 @@ can pass additional arguments that control the code output:
|
|||||||
statement.
|
statement.
|
||||||
|
|
||||||
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
||||||
comments, `"some"` to preserve some comments, a regular expression string
|
comments, `"some"` to preserve multi-line comments that contain `@cc_on`,
|
||||||
(e.g. `/^!/`) or a function.
|
`@license`, or `@preserve` (case-insensitive), a regular expression string
|
||||||
|
(e.g. `/^!/`), or a function which returns `boolean`, e.g.
|
||||||
|
```js
|
||||||
|
function(node, comment) {
|
||||||
|
return comment.value.indexOf("@type " + node.TYPE) >= 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- `indent_level` (default `4`)
|
- `indent_level` (default `4`)
|
||||||
|
|
||||||
|
|||||||
11
bin/uglifyjs
11
bin/uglifyjs
@@ -54,6 +54,7 @@ program.option("--toplevel", "Compress and/or mangle variables in toplevel scope
|
|||||||
program.option("--verbose", "Print diagnostic messages.");
|
program.option("--verbose", "Print diagnostic messages.");
|
||||||
program.option("--warn", "Print warning messages.");
|
program.option("--warn", "Print warning messages.");
|
||||||
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
|
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
|
||||||
|
program.option("--reduce-test", "Reduce a standalone `console.log` based test case.");
|
||||||
program.arguments("[files...]").parseArgv(process.argv);
|
program.arguments("[files...]").parseArgv(process.argv);
|
||||||
if (program.configFile) {
|
if (program.configFile) {
|
||||||
options = JSON.parse(read_file(program.configFile));
|
options = JSON.parse(read_file(program.configFile));
|
||||||
@@ -215,7 +216,15 @@ function run() {
|
|||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
fatal(ex);
|
fatal(ex);
|
||||||
}
|
}
|
||||||
var result = UglifyJS.minify(files, options);
|
if (program.reduceTest) {
|
||||||
|
// load on demand - assumes dev tree checked out
|
||||||
|
var reduce_test = require("../test/reduce");
|
||||||
|
var testcase = files[0] || files[Object.keys(files)[0]];
|
||||||
|
var result = reduce_test(testcase, options, {verbose: true});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var result = UglifyJS.minify(files, options);
|
||||||
|
}
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
var ex = result.error;
|
var ex = result.error;
|
||||||
if (ex.name == "SyntaxError") {
|
if (ex.name == "SyntaxError") {
|
||||||
|
|||||||
@@ -169,10 +169,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
|||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
function walk_body(node, visitor) {
|
function walk_body(node, visitor) {
|
||||||
var body = node.body;
|
node.body.forEach(function(node) {
|
||||||
if (body instanceof AST_Statement) {
|
|
||||||
body._walk(visitor);
|
|
||||||
} else body.forEach(function(node) {
|
|
||||||
node._walk(visitor);
|
node._walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -351,7 +348,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
filename: "wrap=" + JSON.stringify(name)
|
filename: "wrap=" + JSON.stringify(name)
|
||||||
}).transform(new TreeTransformer(function(node) {
|
}).transform(new TreeTransformer(function(node) {
|
||||||
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
||||||
return MAP.splice(body);
|
return List.splice(body);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@@ -370,7 +367,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
filename: "enclose=" + JSON.stringify(args_values)
|
filename: "enclose=" + JSON.stringify(args_values)
|
||||||
}).transform(new TreeTransformer(function(node) {
|
}).transform(new TreeTransformer(function(node) {
|
||||||
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
||||||
return MAP.splice(body);
|
return List.splice(body);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
526
lib/compress.js
526
lib/compress.js
@@ -315,10 +315,10 @@ merge(Compressor.prototype, {
|
|||||||
if (value instanceof AST_Array) return native_fns.Array[name];
|
if (value instanceof AST_Array) return native_fns.Array[name];
|
||||||
if (value instanceof AST_Function) return native_fns.Function[name];
|
if (value instanceof AST_Function) return native_fns.Function[name];
|
||||||
if (value instanceof AST_Object) return native_fns.Object[name];
|
if (value instanceof AST_Object) return native_fns.Object[name];
|
||||||
if (value instanceof AST_RegExp) return native_fns.RegExp[name];
|
if (value instanceof AST_RegExp) return native_fns.RegExp[name] && !value.value.global;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_modified(compressor, tw, node, value, level, immutable) {
|
function is_modified(compressor, tw, node, value, level, immutable, recursive) {
|
||||||
var parent = tw.parent(level);
|
var parent = tw.parent(level);
|
||||||
if (compressor.option("unsafe") && parent instanceof AST_Dot && is_read_only_fn(value, parent.property)) {
|
if (compressor.option("unsafe") && parent instanceof AST_Dot && is_read_only_fn(value, parent.property)) {
|
||||||
return;
|
return;
|
||||||
@@ -342,7 +342,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (parent instanceof AST_PropAccess && parent.expression === node) {
|
if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||||
var prop = read_property(value, parent);
|
var prop = read_property(value, parent);
|
||||||
return !immutable && is_modified(compressor, tw, parent, prop, level + 1);
|
return (!immutable || recursive) && is_modified(compressor, tw, parent, prop, level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,7 +759,8 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else if (d.fixed) {
|
} else if (d.fixed) {
|
||||||
value = this.fixed_value();
|
value = this.fixed_value();
|
||||||
if (recursive_ref(tw, d)) {
|
var recursive = recursive_ref(tw, d);
|
||||||
|
if (recursive) {
|
||||||
d.recursive_refs++;
|
d.recursive_refs++;
|
||||||
} else if (value && ref_once(tw, compressor, d)) {
|
} else if (value && ref_once(tw, compressor, d)) {
|
||||||
d.single_use = value instanceof AST_Lambda && !value.pinned()
|
d.single_use = value instanceof AST_Lambda && !value.pinned()
|
||||||
@@ -767,7 +768,7 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
d.single_use = false;
|
d.single_use = false;
|
||||||
}
|
}
|
||||||
if (is_modified(compressor, tw, this, value, 0, is_immutable(value))) {
|
if (is_modified(compressor, tw, this, value, 0, is_immutable(value), recursive)) {
|
||||||
if (d.single_use) {
|
if (d.single_use) {
|
||||||
d.single_use = "m";
|
d.single_use = "m";
|
||||||
} else {
|
} else {
|
||||||
@@ -995,9 +996,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function needs_unbinding(compressor, val) {
|
function needs_unbinding(compressor, val) {
|
||||||
return val instanceof AST_PropAccess
|
return val instanceof AST_PropAccess
|
||||||
|| compressor.has_directive("use strict")
|
|| is_undeclared_ref(val) && val.name == "eval";
|
||||||
&& is_undeclared_ref(val)
|
|
||||||
&& val.name == "eval";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we shouldn't compress (1,func)(something) to
|
// we shouldn't compress (1,func)(something) to
|
||||||
@@ -1230,7 +1229,7 @@ merge(Compressor.prototype, {
|
|||||||
var parent = multi_replacer.parent();
|
var parent = multi_replacer.parent();
|
||||||
if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
|
if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
|
||||||
value_def.replaced++;
|
value_def.replaced++;
|
||||||
return MAP.skip;
|
return List.skip;
|
||||||
}
|
}
|
||||||
return get_rvalue(candidate);
|
return get_rvalue(candidate);
|
||||||
case 1:
|
case 1:
|
||||||
@@ -1384,7 +1383,10 @@ merge(Compressor.prototype, {
|
|||||||
function is_last_node(node, parent) {
|
function is_last_node(node, parent) {
|
||||||
if (node instanceof AST_Call) {
|
if (node instanceof AST_Call) {
|
||||||
var fn = node.expression;
|
var fn = node.expression;
|
||||||
if (fn instanceof AST_SymbolRef) fn = fn.fixed_value();
|
if (fn instanceof AST_SymbolRef) {
|
||||||
|
if (fn.definition().recursive_refs > 0) return true;
|
||||||
|
fn = fn.fixed_value();
|
||||||
|
}
|
||||||
if (!(fn instanceof AST_Lambda)) return true;
|
if (!(fn instanceof AST_Lambda)) return true;
|
||||||
if (fn.collapse_scanning) return false;
|
if (fn.collapse_scanning) return false;
|
||||||
fn.collapse_scanning = true;
|
fn.collapse_scanning = true;
|
||||||
@@ -1863,7 +1865,7 @@ merge(Compressor.prototype, {
|
|||||||
node.value = null;
|
node.value = null;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
return in_list ? MAP.skip : null;
|
return in_list ? List.skip : null;
|
||||||
}, patch_sequence));
|
}, patch_sequence));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2528,9 +2530,8 @@ merge(Compressor.prototype, {
|
|||||||
return left.is_negative_zero() || right.is_negative_zero();
|
return left.is_negative_zero() || right.is_negative_zero();
|
||||||
case "*":
|
case "*":
|
||||||
case "/":
|
case "/":
|
||||||
return true;
|
|
||||||
case "%":
|
case "%":
|
||||||
return left.is_negative_zero();
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3003,6 +3004,7 @@ merge(Compressor.prototype, {
|
|||||||
].concat(object_fns),
|
].concat(object_fns),
|
||||||
Object: object_fns,
|
Object: object_fns,
|
||||||
RegExp: [
|
RegExp: [
|
||||||
|
"exec",
|
||||||
"test",
|
"test",
|
||||||
].concat(object_fns),
|
].concat(object_fns),
|
||||||
String: [
|
String: [
|
||||||
@@ -3071,15 +3073,21 @@ merge(Compressor.prototype, {
|
|||||||
// If the node has been successfully reduced to a constant,
|
// If the node has been successfully reduced to a constant,
|
||||||
// then its value is returned; otherwise the element itself
|
// then its value is returned; otherwise the element itself
|
||||||
// is returned.
|
// is returned.
|
||||||
|
//
|
||||||
// They can be distinguished as constant value is never a
|
// They can be distinguished as constant value is never a
|
||||||
// descendant of AST_Node.
|
// descendant of AST_Node.
|
||||||
AST_Node.DEFMETHOD("evaluate", function(compressor) {
|
//
|
||||||
|
// When `ignore_side_effects` is `true`, inspect the constant value
|
||||||
|
// produced without worrying about any side effects caused by said
|
||||||
|
// expression.
|
||||||
|
AST_Node.DEFMETHOD("evaluate", function(compressor, ignore_side_effects) {
|
||||||
if (!compressor.option("evaluate")) return this;
|
if (!compressor.option("evaluate")) return this;
|
||||||
var cached = [];
|
var cached = [];
|
||||||
var val = this._eval(compressor, cached, 1);
|
var val = this._eval(compressor, ignore_side_effects, cached, 1);
|
||||||
cached.forEach(function(node) {
|
cached.forEach(function(node) {
|
||||||
delete node._eval;
|
delete node._eval;
|
||||||
});
|
});
|
||||||
|
if (ignore_side_effects) return val;
|
||||||
if (!val || val instanceof RegExp) return val;
|
if (!val || val instanceof RegExp) return val;
|
||||||
if (typeof val == "function" || typeof val == "object") return this;
|
if (typeof val == "function" || typeof val == "object") return this;
|
||||||
return val;
|
return val;
|
||||||
@@ -3104,6 +3112,19 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Constant, function() {
|
def(AST_Constant, function() {
|
||||||
return this.value;
|
return this.value;
|
||||||
});
|
});
|
||||||
|
def(AST_Assign, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
|
if (!ignore_side_effects) return this;
|
||||||
|
if (this.operator != "=") return this;
|
||||||
|
var node = this.right;
|
||||||
|
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
|
return value === node ? this : value;
|
||||||
|
});
|
||||||
|
def(AST_Sequence, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
|
if (!ignore_side_effects) return this;
|
||||||
|
var node = this.tail_node();
|
||||||
|
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
|
return value === node ? this : value;
|
||||||
|
});
|
||||||
def(AST_Function, function(compressor) {
|
def(AST_Function, function(compressor) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var fn = function() {};
|
var fn = function() {};
|
||||||
@@ -3115,12 +3136,12 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Array, function(compressor, cached, depth) {
|
def(AST_Array, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var elements = [];
|
var elements = [];
|
||||||
for (var i = 0; i < this.elements.length; i++) {
|
for (var i = 0; i < this.elements.length; i++) {
|
||||||
var element = this.elements[i];
|
var element = this.elements[i];
|
||||||
var value = element._eval(compressor, cached, depth);
|
var value = element._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (element === value) return this;
|
if (element === value) return this;
|
||||||
elements.push(value);
|
elements.push(value);
|
||||||
}
|
}
|
||||||
@@ -3128,7 +3149,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor, cached, depth) {
|
def(AST_Object, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var val = {};
|
var val = {};
|
||||||
for (var i = 0; i < this.properties.length; i++) {
|
for (var i = 0; i < this.properties.length; i++) {
|
||||||
@@ -3137,14 +3158,14 @@ merge(Compressor.prototype, {
|
|||||||
if (key instanceof AST_Symbol) {
|
if (key instanceof AST_Symbol) {
|
||||||
key = key.name;
|
key = key.name;
|
||||||
} else if (key instanceof AST_Node) {
|
} else if (key instanceof AST_Node) {
|
||||||
key = key._eval(compressor, cached, depth);
|
key = key._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (key === prop.key) return this;
|
if (key === prop.key) return this;
|
||||||
}
|
}
|
||||||
if (typeof Object.prototype[key] === 'function') {
|
if (typeof Object.prototype[key] === 'function') {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (prop.value instanceof AST_Function) continue;
|
if (prop.value instanceof AST_Function) continue;
|
||||||
val[key] = prop.value._eval(compressor, cached, depth);
|
val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (val[key] === prop.value) return this;
|
if (val[key] === prop.value) return this;
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
@@ -3152,7 +3173,7 @@ merge(Compressor.prototype, {
|
|||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
var non_converting_unary = makePredicate("! typeof void");
|
var non_converting_unary = makePredicate("! typeof void");
|
||||||
def(AST_UnaryPrefix, function(compressor, cached, depth) {
|
def(AST_UnaryPrefix, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
var e = this.expression;
|
var e = this.expression;
|
||||||
// Function would be evaluated to an array and so typeof would
|
// Function would be evaluated to an array and so typeof would
|
||||||
// incorrectly return 'object'. Hence making is a special case.
|
// incorrectly return 'object'. Hence making is a special case.
|
||||||
@@ -3164,7 +3185,7 @@ merge(Compressor.prototype, {
|
|||||||
return typeof function(){};
|
return typeof function(){};
|
||||||
}
|
}
|
||||||
if (!non_converting_unary[this.operator]) depth++;
|
if (!non_converting_unary[this.operator]) depth++;
|
||||||
var v = e._eval(compressor, cached, depth);
|
var v = e._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (v === this.expression) return this;
|
if (v === this.expression) return this;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "!": return !v;
|
case "!": return !v;
|
||||||
@@ -3187,12 +3208,12 @@ merge(Compressor.prototype, {
|
|||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
var non_converting_binary = makePredicate("&& || === !==");
|
var non_converting_binary = makePredicate("&& || === !==");
|
||||||
def(AST_Binary, function(compressor, cached, depth) {
|
def(AST_Binary, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
if (!non_converting_binary[this.operator]) depth++;
|
if (!non_converting_binary[this.operator]) depth++;
|
||||||
var left = this.left._eval(compressor, cached, depth);
|
var left = this.left._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (left === this.left) return this;
|
if (left === this.left) return this;
|
||||||
if (this.operator == (left ? "||" : "&&")) return left;
|
if (this.operator == (left ? "||" : "&&")) return left;
|
||||||
var right = this.right._eval(compressor, cached, depth);
|
var right = this.right._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (right === this.right) return this;
|
if (right === this.right) return this;
|
||||||
var result;
|
var result;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
@@ -3221,6 +3242,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (isNaN(result)) return compressor.find_parent(AST_With) ? this : result;
|
if (isNaN(result)) return compressor.find_parent(AST_With) ? this : result;
|
||||||
if (compressor.option("unsafe_math")
|
if (compressor.option("unsafe_math")
|
||||||
|
&& !ignore_side_effects
|
||||||
&& result
|
&& result
|
||||||
&& typeof result == "number"
|
&& typeof result == "number"
|
||||||
&& (this.operator == "+" || this.operator == "-")) {
|
&& (this.operator == "+" || this.operator == "-")) {
|
||||||
@@ -3235,14 +3257,14 @@ merge(Compressor.prototype, {
|
|||||||
return (match[1] || ".").length - 1 - (match[2] || "").slice(1);
|
return (match[1] || ".").length - 1 - (match[2] || "").slice(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor, cached, depth) {
|
def(AST_Conditional, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
var condition = this.condition._eval(compressor, cached, depth);
|
var condition = this.condition._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (condition === this.condition) return this;
|
if (condition === this.condition) return this;
|
||||||
var node = condition ? this.consequent : this.alternative;
|
var node = condition ? this.consequent : this.alternative;
|
||||||
var value = node._eval(compressor, cached, depth);
|
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
return value === node ? this : value;
|
return value === node ? this : value;
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor, cached, depth) {
|
def(AST_SymbolRef, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
if (!fixed) return this;
|
if (!fixed) return this;
|
||||||
var value;
|
var value;
|
||||||
@@ -3250,7 +3272,7 @@ merge(Compressor.prototype, {
|
|||||||
value = fixed._eval();
|
value = fixed._eval();
|
||||||
} else {
|
} else {
|
||||||
this._eval = return_this;
|
this._eval = return_this;
|
||||||
value = fixed._eval(compressor, cached, depth);
|
value = fixed._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
delete this._eval;
|
delete this._eval;
|
||||||
if (value === fixed) return this;
|
if (value === fixed) return this;
|
||||||
fixed._eval = function() {
|
fixed._eval = function() {
|
||||||
@@ -3307,11 +3329,11 @@ merge(Compressor.prototype, {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
var regexp_props = makePredicate("global ignoreCase multiline source");
|
var regexp_props = makePredicate("global ignoreCase multiline source");
|
||||||
def(AST_PropAccess, function(compressor, cached, depth) {
|
def(AST_PropAccess, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var key = this.property;
|
var key = this.property;
|
||||||
if (key instanceof AST_Node) {
|
if (key instanceof AST_Node) {
|
||||||
key = key._eval(compressor, cached, depth);
|
key = key._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (key === this.property) return this;
|
if (key === this.property) return this;
|
||||||
}
|
}
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
@@ -3321,7 +3343,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!static_value || !static_value[key]) return this;
|
if (!static_value || !static_value[key]) return this;
|
||||||
val = global_objs[exp.name];
|
val = global_objs[exp.name];
|
||||||
} else {
|
} else {
|
||||||
val = exp._eval(compressor, cached, depth + 1);
|
val = exp._eval(compressor, ignore_side_effects, cached, depth + 1);
|
||||||
if (val == null || val === exp) return this;
|
if (val == null || val === exp) return this;
|
||||||
if (val instanceof RegExp) {
|
if (val instanceof RegExp) {
|
||||||
if (!regexp_props[key]) return this;
|
if (!regexp_props[key]) return this;
|
||||||
@@ -3340,7 +3362,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
def(AST_Call, function(compressor, cached, depth) {
|
def(AST_Call, function(compressor, ignore_side_effects, cached, depth) {
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
if (fn instanceof AST_Lambda) {
|
if (fn instanceof AST_Lambda) {
|
||||||
@@ -3351,24 +3373,27 @@ merge(Compressor.prototype, {
|
|||||||
var args = eval_args(this.args);
|
var args = eval_args(this.args);
|
||||||
if (!args) return this;
|
if (!args) return this;
|
||||||
if (!stat.value) return undefined;
|
if (!stat.value) return undefined;
|
||||||
fn.argnames.forEach(function(sym, i) {
|
if (!all(fn.argnames, function(sym, i) {
|
||||||
var value = args[i];
|
var value = args[i];
|
||||||
sym.definition().references.forEach(function(node) {
|
var def = sym.definition();
|
||||||
|
if (def.orig[def.orig.length - 1] !== sym) return false;
|
||||||
|
def.references.forEach(function(node) {
|
||||||
node._eval = function() {
|
node._eval = function() {
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
cached.push(node);
|
cached.push(node);
|
||||||
});
|
});
|
||||||
});
|
return true;
|
||||||
|
})) return this;
|
||||||
fn.evaluating = true;
|
fn.evaluating = true;
|
||||||
var val = stat.value._eval(compressor, cached, depth);
|
var val = stat.value._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
delete fn.evaluating;
|
delete fn.evaluating;
|
||||||
if (val === stat.value) return this;
|
if (val === stat.value) return this;
|
||||||
return val;
|
return val;
|
||||||
} else if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
} else if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
||||||
var key = exp.property;
|
var key = exp.property;
|
||||||
if (key instanceof AST_Node) {
|
if (key instanceof AST_Node) {
|
||||||
key = key._eval(compressor, cached, depth);
|
key = key._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (key === exp.property) return this;
|
if (key === exp.property) return this;
|
||||||
}
|
}
|
||||||
var val;
|
var val;
|
||||||
@@ -3378,10 +3403,11 @@ merge(Compressor.prototype, {
|
|||||||
if (!static_fn || !static_fn[key]) return this;
|
if (!static_fn || !static_fn[key]) return this;
|
||||||
val = global_objs[e.name];
|
val = global_objs[e.name];
|
||||||
} else {
|
} else {
|
||||||
val = e._eval(compressor, cached, depth + 1);
|
val = e._eval(compressor, ignore_side_effects, cached, depth + 1);
|
||||||
if (val == null || val === e) return this;
|
if (val == null || val === e) return this;
|
||||||
var native_fn = native_fns[val.constructor.name];
|
var native_fn = native_fns[val.constructor.name];
|
||||||
if (!native_fn || !native_fn[key]) return this;
|
if (!native_fn || !native_fn[key]) return this;
|
||||||
|
if (val instanceof RegExp && val.global && !(e instanceof AST_RegExp)) return this;
|
||||||
}
|
}
|
||||||
var args = eval_args(this.args);
|
var args = eval_args(this.args);
|
||||||
if (!args) return this;
|
if (!args) return this;
|
||||||
@@ -3395,6 +3421,8 @@ merge(Compressor.prototype, {
|
|||||||
line: this.start.line,
|
line: this.start.line,
|
||||||
col: this.start.col
|
col: this.start.col
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
if (val instanceof RegExp) val.lastIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@@ -3403,7 +3431,7 @@ merge(Compressor.prototype, {
|
|||||||
var values = [];
|
var values = [];
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
var arg = args[i];
|
var arg = args[i];
|
||||||
var value = arg._eval(compressor, cached, depth);
|
var value = arg._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
if (arg === value) return;
|
if (arg === value) return;
|
||||||
values.push(value);
|
values.push(value);
|
||||||
}
|
}
|
||||||
@@ -3891,14 +3919,18 @@ merge(Compressor.prototype, {
|
|||||||
} else if (node instanceof AST_Unary) {
|
} else if (node instanceof AST_Unary) {
|
||||||
if (node.write_only) sym = node.expression;
|
if (node.write_only) sym = node.expression;
|
||||||
}
|
}
|
||||||
if (!/strict/.test(compressor.option("pure_getters"))) return sym instanceof AST_SymbolRef && sym;
|
if (/strict/.test(compressor.option("pure_getters"))) {
|
||||||
while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) {
|
while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) {
|
||||||
if (sym instanceof AST_Sub) props.unshift(sym.property);
|
if (sym instanceof AST_Sub) props.unshift(sym.property);
|
||||||
sym = sym.expression;
|
sym = sym.expression;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sym instanceof AST_SymbolRef && all(sym.definition().orig, function(sym) {
|
if (!(sym instanceof AST_SymbolRef)) return;
|
||||||
|
if (compressor.exposed(sym.definition())) return;
|
||||||
|
if (!all(sym.definition().orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolLambda);
|
return !(sym instanceof AST_SymbolLambda);
|
||||||
}) && sym;
|
})) return;
|
||||||
|
return sym;
|
||||||
};
|
};
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
@@ -3988,6 +4020,8 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
var unused_fn_names = [];
|
var unused_fn_names = [];
|
||||||
|
var calls_to_drop_args = [];
|
||||||
|
var fns_with_marked_args = [];
|
||||||
var tt = new TreeTransformer(function(node, descend, in_list) {
|
var tt = new TreeTransformer(function(node, descend, in_list) {
|
||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
@@ -4017,7 +4051,7 @@ merge(Compressor.prototype, {
|
|||||||
if (value) props.push(value);
|
if (value) props.push(value);
|
||||||
switch (props.length) {
|
switch (props.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return MAP.skip;
|
return List.skip;
|
||||||
case 1:
|
case 1:
|
||||||
return maintain_this_binding(compressor, parent, node, props[0].transform(tt));
|
return maintain_this_binding(compressor, parent, node, props[0].transform(tt));
|
||||||
default:
|
default:
|
||||||
@@ -4028,6 +4062,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
||||||
if (scope !== self) return;
|
if (scope !== self) return;
|
||||||
if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
|
if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
|
||||||
unused_fn_names.push(node);
|
unused_fn_names.push(node);
|
||||||
@@ -4046,6 +4081,7 @@ merge(Compressor.prototype, {
|
|||||||
trim = false;
|
trim = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fns_with_marked_args.push(node);
|
||||||
}
|
}
|
||||||
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
@@ -4159,11 +4195,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
switch (body.length) {
|
switch (body.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
case 1:
|
case 1:
|
||||||
return body[0];
|
return body[0];
|
||||||
default:
|
default:
|
||||||
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
|
return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -4177,7 +4213,7 @@ merge(Compressor.prototype, {
|
|||||||
var block = node.body;
|
var block = node.body;
|
||||||
node.body = block.body.pop();
|
node.body = block.body.pop();
|
||||||
block.body.push(node);
|
block.body.push(node);
|
||||||
return in_list ? MAP.splice(block.body) : block;
|
return in_list ? List.splice(block.body) : block;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -4214,7 +4250,7 @@ merge(Compressor.prototype, {
|
|||||||
} else if (is_empty(node.init)) {
|
} else if (is_empty(node.init)) {
|
||||||
node.init = null;
|
node.init = null;
|
||||||
}
|
}
|
||||||
return !block ? node : in_list ? MAP.splice(block.body) : block;
|
return !block ? node : in_list ? List.splice(block.body) : block;
|
||||||
} else if (node instanceof AST_ForIn) {
|
} else if (node instanceof AST_ForIn) {
|
||||||
if (!drop_vars || !compressor.option("loops")) return;
|
if (!drop_vars || !compressor.option("loops")) return;
|
||||||
if (!(node.init instanceof AST_Definitions)) return;
|
if (!(node.init instanceof AST_Definitions)) return;
|
||||||
@@ -4229,7 +4265,7 @@ merge(Compressor.prototype, {
|
|||||||
body: value
|
body: value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
} else if (node instanceof AST_Sequence) {
|
} else if (node instanceof AST_Sequence) {
|
||||||
if (node.expressions.length == 1) return node.expressions[0];
|
if (node.expressions.length == 1) return node.expressions[0];
|
||||||
}
|
}
|
||||||
@@ -4239,6 +4275,9 @@ merge(Compressor.prototype, {
|
|||||||
unused_fn_names.forEach(function(fn) {
|
unused_fn_names.forEach(function(fn) {
|
||||||
fn.name = null;
|
fn.name = null;
|
||||||
});
|
});
|
||||||
|
calls_to_drop_args.forEach(function(call) {
|
||||||
|
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
||||||
|
});
|
||||||
|
|
||||||
function log(sym, text, props) {
|
function log(sym, text, props) {
|
||||||
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
||||||
@@ -4478,7 +4517,7 @@ merge(Compressor.prototype, {
|
|||||||
node.in_bool = true;
|
node.in_bool = true;
|
||||||
var value = node.value;
|
var value = node.value;
|
||||||
if (value) {
|
if (value) {
|
||||||
var ev = value.is_truthy() || value.tail_node().evaluate(compressor);
|
var ev = value.is_truthy() || value.evaluate(compressor, true);
|
||||||
if (!ev) {
|
if (!ev) {
|
||||||
value = value.drop_side_effect_free(compressor);
|
value = value.drop_side_effect_free(compressor);
|
||||||
node.value = value ? make_sequence(node.value, [
|
node.value = value ? make_sequence(node.value, [
|
||||||
@@ -4610,7 +4649,7 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
defs_by_id[node.name.definition().id] = defs;
|
defs_by_id[node.name.definition().id] = defs;
|
||||||
return MAP.splice(var_defs);
|
return List.splice(var_defs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_sym(sym, key) {
|
function make_sym(sym, key) {
|
||||||
@@ -4746,21 +4785,17 @@ merge(Compressor.prototype, {
|
|||||||
return exprs && make_sequence(this, exprs);
|
return exprs && make_sequence(this, exprs);
|
||||||
}
|
}
|
||||||
if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) {
|
if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) {
|
||||||
var node = this.clone();
|
|
||||||
exp.process_expression(false, function(node) {
|
exp.process_expression(false, function(node) {
|
||||||
var value = node.value && node.value.drop_side_effect_free(compressor, true);
|
var value = node.value && node.value.drop_side_effect_free(compressor, true);
|
||||||
return value ? make_node(AST_SimpleStatement, node, {
|
return value ? make_node(AST_SimpleStatement, node, {
|
||||||
body: value
|
body: value
|
||||||
}) : make_node(AST_EmptyStatement, node);
|
}) : make_node(AST_EmptyStatement, node);
|
||||||
});
|
});
|
||||||
exp.walk(new TreeWalker(function(node) {
|
scan_local_returns(exp, function(node) {
|
||||||
if (node instanceof AST_Return && node.value) {
|
if (node.value) node.value = node.value.drop_side_effect_free(compressor);
|
||||||
node.value = node.value.drop_side_effect_free(compressor);
|
});
|
||||||
return true;
|
// always shallow clone to ensure stripping of negated IIFEs
|
||||||
}
|
return this.clone();
|
||||||
if (node instanceof AST_Scope && node !== exp) return true;
|
|
||||||
}));
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -4878,7 +4913,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Do, function(self, compressor) {
|
OPT(AST_Do, function(self, compressor) {
|
||||||
if (!compressor.option("loops")) return self;
|
if (!compressor.option("loops")) return self;
|
||||||
var cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
|
var cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
||||||
if (!(cond instanceof AST_Node)) {
|
if (!(cond instanceof AST_Node)) {
|
||||||
if (cond) return make_node(AST_For, self, {
|
if (cond) return make_node(AST_For, self, {
|
||||||
body: make_node(AST_BlockStatement, self.body, {
|
body: make_node(AST_BlockStatement, self.body, {
|
||||||
@@ -5008,16 +5043,14 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (self.condition) {
|
if (self.condition) {
|
||||||
var cond = self.condition.evaluate(compressor);
|
var cond = self.condition.evaluate(compressor);
|
||||||
if (!(cond instanceof AST_Node)) {
|
|
||||||
if (cond) self.condition = null;
|
|
||||||
else if (!compressor.option("dead_code")) {
|
|
||||||
var orig = self.condition;
|
|
||||||
self.condition = make_node_from_constant(cond, self.condition);
|
|
||||||
self.condition = best_of_expression(self.condition.transform(compressor), orig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cond instanceof AST_Node) {
|
if (cond instanceof AST_Node) {
|
||||||
cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
|
cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
||||||
|
} else if (cond) {
|
||||||
|
self.condition = null;
|
||||||
|
} else if (!compressor.option("dead_code")) {
|
||||||
|
var orig = self.condition;
|
||||||
|
self.condition = make_node_from_constant(cond, self.condition);
|
||||||
|
self.condition = best_of_expression(self.condition.transform(compressor), orig);
|
||||||
}
|
}
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
@@ -5109,7 +5142,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
if (cond instanceof AST_Node) {
|
if (cond instanceof AST_Node) {
|
||||||
cond = self.condition.is_truthy() || self.condition.tail_node().evaluate(compressor);
|
cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
||||||
}
|
}
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
||||||
@@ -5255,7 +5288,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (!compressor.option("dead_code")) return self;
|
if (!compressor.option("dead_code")) return self;
|
||||||
if (value instanceof AST_Node) {
|
if (value instanceof AST_Node) {
|
||||||
value = self.expression.tail_node().evaluate(compressor);
|
value = self.expression.evaluate(compressor, true);
|
||||||
}
|
}
|
||||||
var decl = [];
|
var decl = [];
|
||||||
var body = [];
|
var body = [];
|
||||||
@@ -5277,7 +5310,7 @@ merge(Compressor.prototype, {
|
|||||||
eliminate_branch(branch, body[body.length - 1]);
|
eliminate_branch(branch, body[body.length - 1]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (exp instanceof AST_Node) exp = branch.expression.tail_node().evaluate(compressor);
|
if (exp instanceof AST_Node) exp = branch.expression.evaluate(compressor, true);
|
||||||
if (exp === value) {
|
if (exp === value) {
|
||||||
exact_match = branch;
|
exact_match = branch;
|
||||||
if (default_branch) {
|
if (default_branch) {
|
||||||
@@ -5437,6 +5470,62 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(node, x);
|
return make_sequence(node, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drop_unused_call_args(call, compressor, fns_with_marked_args) {
|
||||||
|
var exp = call.expression;
|
||||||
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
|
if (!(fn instanceof AST_Lambda)) return;
|
||||||
|
if (fn.uses_arguments) return;
|
||||||
|
if (fn.pinned()) return;
|
||||||
|
if (fns_with_marked_args && fns_with_marked_args.indexOf(fn) < 0) return;
|
||||||
|
var args = call.args;
|
||||||
|
var pos = 0, last = 0;
|
||||||
|
var drop_fargs = fn === exp && !fn.name && compressor.drop_fargs(fn, call);
|
||||||
|
var side_effects = [];
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var trim = i >= fn.argnames.length;
|
||||||
|
if (trim || fn.argnames[i].__unused) {
|
||||||
|
var node = args[i].drop_side_effect_free(compressor);
|
||||||
|
if (drop_fargs) {
|
||||||
|
fn.argnames.splice(i, 1);
|
||||||
|
args.splice(i, 1);
|
||||||
|
if (node) side_effects.push(node);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
} else if (node) {
|
||||||
|
side_effects.push(node);
|
||||||
|
args[pos++] = make_sequence(call, side_effects);
|
||||||
|
side_effects = [];
|
||||||
|
} else if (!trim) {
|
||||||
|
if (side_effects.length) {
|
||||||
|
node = make_sequence(call, side_effects);
|
||||||
|
side_effects = [];
|
||||||
|
} else {
|
||||||
|
node = make_node(AST_Number, args[i], {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
args[pos++] = node;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
side_effects.push(args[i]);
|
||||||
|
args[pos++] = make_sequence(call, side_effects);
|
||||||
|
side_effects = [];
|
||||||
|
}
|
||||||
|
last = pos;
|
||||||
|
}
|
||||||
|
if (drop_fargs) for (; i < fn.argnames.length; i++) {
|
||||||
|
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
|
||||||
|
}
|
||||||
|
args.length = last;
|
||||||
|
if (!side_effects.length) return;
|
||||||
|
var arg = make_sequence(call, side_effects);
|
||||||
|
args.push(args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, call, {
|
||||||
|
operator: "void",
|
||||||
|
expression: arg
|
||||||
|
}) : arg);
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Call, function(self, compressor) {
|
OPT(AST_Call, function(self, compressor) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.option("sequences")) {
|
||||||
@@ -5453,63 +5542,7 @@ merge(Compressor.prototype, {
|
|||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var fn = exp;
|
if (compressor.option("unused")) drop_unused_call_args(self, compressor);
|
||||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
|
||||||
fn = fn.fixed_value();
|
|
||||||
}
|
|
||||||
var is_func = fn instanceof AST_Lambda;
|
|
||||||
if (compressor.option("unused")
|
|
||||||
&& is_func
|
|
||||||
&& !fn.uses_arguments
|
|
||||||
&& !fn.pinned()) {
|
|
||||||
var pos = 0, last = 0;
|
|
||||||
var drop_fargs = exp === fn && !fn.name && compressor.drop_fargs(fn, self);
|
|
||||||
var side_effects = [];
|
|
||||||
for (var i = 0; i < self.args.length; i++) {
|
|
||||||
var trim = i >= fn.argnames.length;
|
|
||||||
if (trim || fn.argnames[i].__unused) {
|
|
||||||
var node = self.args[i].drop_side_effect_free(compressor);
|
|
||||||
if (drop_fargs) {
|
|
||||||
fn.argnames.splice(i, 1);
|
|
||||||
self.args.splice(i, 1);
|
|
||||||
if (node) side_effects.push(node);
|
|
||||||
i--;
|
|
||||||
continue;
|
|
||||||
} else if (node) {
|
|
||||||
side_effects.push(node);
|
|
||||||
self.args[pos++] = make_sequence(self, side_effects);
|
|
||||||
side_effects = [];
|
|
||||||
} else if (!trim) {
|
|
||||||
if (side_effects.length) {
|
|
||||||
node = make_sequence(self, side_effects);
|
|
||||||
side_effects = [];
|
|
||||||
} else {
|
|
||||||
node = make_node(AST_Number, self.args[i], {
|
|
||||||
value: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.args[pos++] = node;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
side_effects.push(self.args[i]);
|
|
||||||
self.args[pos++] = make_sequence(self, side_effects);
|
|
||||||
side_effects = [];
|
|
||||||
}
|
|
||||||
last = pos;
|
|
||||||
}
|
|
||||||
if (drop_fargs) for (; i < fn.argnames.length; i++) {
|
|
||||||
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
|
|
||||||
}
|
|
||||||
self.args.length = last;
|
|
||||||
if (side_effects.length) {
|
|
||||||
var arg = make_sequence(self, side_effects);
|
|
||||||
self.args.push(self.args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, self, {
|
|
||||||
operator: "void",
|
|
||||||
expression: arg
|
|
||||||
}) : arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
@@ -5775,33 +5808,58 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
|
var is_func = fn instanceof AST_Lambda;
|
||||||
var stat = is_func && fn.first_statement();
|
var stat = is_func && fn.first_statement();
|
||||||
var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
|
var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||||
if (exp === fn && can_inline && stat instanceof AST_Return) {
|
if (can_inline && stat instanceof AST_Return) {
|
||||||
var value = stat.value;
|
var value = stat.value;
|
||||||
if (!value || value.is_constant_expression()) {
|
if (exp === fn && (!value || value.is_constant_expression())) {
|
||||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
||||||
return make_sequence(self, args).optimize(compressor);
|
return make_sequence(self, args).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_func) {
|
if (is_func) {
|
||||||
var def, value, scope, in_loop, level = -1;
|
var def, value, var_assigned = false;
|
||||||
if (can_inline
|
if (can_inline
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.pinned()
|
&& !fn.pinned()
|
||||||
&& !(fn.name && fn instanceof AST_Function)
|
&& !(fn.name && fn instanceof AST_Function)
|
||||||
&& (value = can_flatten_body(stat))
|
&& (value = can_flatten_body(stat))
|
||||||
&& (exp === fn
|
&& (exp === fn
|
||||||
|| compressor.option("unused")
|
|| !recursive_ref(compressor, def = exp.definition()) && fn.is_constant_expression(exp.scope))
|
||||||
&& (def = exp.definition()).references.length == 1
|
&& !fn.contains_this()) {
|
||||||
&& !recursive_ref(compressor, def)
|
if (can_substitute_directly()) {
|
||||||
&& fn.is_constant_expression(exp.scope))
|
var args = self.args.slice();
|
||||||
&& !self.pure
|
args.push(value.clone(true).transform(new TreeTransformer(function(node) {
|
||||||
&& !fn.contains_this()
|
if (node instanceof AST_SymbolRef) {
|
||||||
&& can_inject_symbols()) {
|
var def = node.definition();
|
||||||
fn._squeezed = true;
|
if (fn.variables.get(node.name) !== def) {
|
||||||
if (exp !== fn) fn.parent_scope = exp.scope;
|
if (exp !== fn) def.references.push(node);
|
||||||
return make_sequence(self, flatten_fn()).optimize(compressor);
|
return node;
|
||||||
|
}
|
||||||
|
var index = resolve_index(def);
|
||||||
|
var arg = args[index];
|
||||||
|
if (!arg) return make_node(AST_Undefined, self);
|
||||||
|
args[index] = null;
|
||||||
|
var parent = this.parent();
|
||||||
|
return parent ? maintain_this_binding(compressor, parent, node, arg) : arg;
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
var node = make_sequence(self, args.filter(function(arg) {
|
||||||
|
return arg;
|
||||||
|
})).optimize(compressor);
|
||||||
|
node = maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
||||||
|
if (best_of(compressor, self, node) === node) return node;
|
||||||
|
}
|
||||||
|
var scope, in_loop, level = -1;
|
||||||
|
if ((exp === fn || compressor.option("unused") && exp.definition().references.length == 1)
|
||||||
|
&& can_inject_symbols()) {
|
||||||
|
fn._squeezed = true;
|
||||||
|
if (exp !== fn) fn.parent_scope = exp.scope;
|
||||||
|
var node = make_sequence(self, flatten_fn()).optimize(compressor);
|
||||||
|
return maintain_this_binding(compressor, compressor.parent(), compressor.self(), node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects")
|
if (compressor.option("side_effects")
|
||||||
&& all(fn.body, is_empty)
|
&& all(fn.body, is_empty)
|
||||||
@@ -5851,10 +5909,12 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
var line = fn.body[i];
|
var line = fn.body[i];
|
||||||
if (line instanceof AST_Var) {
|
if (line instanceof AST_Var) {
|
||||||
if (stat && !all(line.definitions, function(var_def) {
|
var assigned = var_assigned || !all(line.definitions, function(var_def) {
|
||||||
return !var_def.value;
|
return !var_def.value;
|
||||||
})) {
|
});
|
||||||
return false;
|
if (assigned) {
|
||||||
|
var_assigned = true;
|
||||||
|
if (stat) return false;
|
||||||
}
|
}
|
||||||
} else if (line instanceof AST_Defun || line instanceof AST_EmptyStatement) {
|
} else if (line instanceof AST_Defun || line instanceof AST_EmptyStatement) {
|
||||||
continue;
|
continue;
|
||||||
@@ -5867,6 +5927,61 @@ merge(Compressor.prototype, {
|
|||||||
return return_value(stat);
|
return return_value(stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolve_index(def) {
|
||||||
|
for (var i = fn.argnames.length; --i >= 0;) {
|
||||||
|
if (fn.argnames[i].definition() === def) return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function can_substitute_directly() {
|
||||||
|
if (var_assigned) return;
|
||||||
|
if (compressor.option("inline") <= 1 && fn.argnames.length) return;
|
||||||
|
if (!fn.variables.all(function(def) {
|
||||||
|
return def.references.length < 2 && def.orig[0] instanceof AST_SymbolFunarg;
|
||||||
|
})) return;
|
||||||
|
var abort = false;
|
||||||
|
var begin;
|
||||||
|
var in_order = [];
|
||||||
|
var side_effects = false;
|
||||||
|
value.walk(new TreeWalker(function(node) {
|
||||||
|
if (abort) return true;
|
||||||
|
if (node instanceof AST_Binary && lazy_op[node.operator]
|
||||||
|
|| node instanceof AST_Conditional) {
|
||||||
|
in_order = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Scope) return abort = true;
|
||||||
|
var def;
|
||||||
|
if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === (def = node.definition())) {
|
||||||
|
if (def.init instanceof AST_Defun) return abort = true;
|
||||||
|
if (is_lhs(node, this.parent())) return abort = true;
|
||||||
|
var index = resolve_index(def);
|
||||||
|
if (!(begin < index)) begin = index;
|
||||||
|
if (!in_order) return;
|
||||||
|
if (side_effects) {
|
||||||
|
in_order = null;
|
||||||
|
} else {
|
||||||
|
in_order.push(fn.argnames[index]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node.has_side_effects(compressor)) side_effects = true;
|
||||||
|
}));
|
||||||
|
if (abort) return;
|
||||||
|
var end = self.args.length;
|
||||||
|
if (in_order && fn.argnames.length >= end) {
|
||||||
|
end = fn.argnames.length;
|
||||||
|
while (end-- > begin && fn.argnames[end] === in_order.pop());
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
var scope = side_effects && compressor.find_parent(AST_Scope);
|
||||||
|
return end <= begin || all(self.args.slice(begin, end), side_effects ? function(funarg) {
|
||||||
|
return funarg.is_constant_expression(scope);
|
||||||
|
} : function(funarg) {
|
||||||
|
return !funarg.has_side_effects(compressor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function var_exists(defined, name) {
|
function var_exists(defined, name) {
|
||||||
return defined[name] || identifier_atom[name] || scope.var_names()[name];
|
return defined[name] || identifier_atom[name] || scope.var_names()[name];
|
||||||
}
|
}
|
||||||
@@ -6162,34 +6277,43 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
|
AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
|
||||||
if (compressor.option("sequences")) {
|
if (this.left instanceof AST_PropAccess) {
|
||||||
if (this.left instanceof AST_Sequence) {
|
if (!(this.left.expression instanceof AST_Sequence)) return this;
|
||||||
var x = this.left.expressions.slice();
|
var x = this.left.expression.expressions.slice();
|
||||||
var e = this.clone();
|
var e = this.clone();
|
||||||
e.left = x.pop();
|
e.left = e.left.clone();
|
||||||
x.push(e);
|
e.left.expression = x.pop();
|
||||||
return make_sequence(this, x).optimize(compressor);
|
x.push(e);
|
||||||
|
return make_sequence(this, x);
|
||||||
|
}
|
||||||
|
if (this.left instanceof AST_Sequence) {
|
||||||
|
var x = this.left.expressions.slice();
|
||||||
|
var e = this.clone();
|
||||||
|
e.left = x.pop();
|
||||||
|
x.push(e);
|
||||||
|
return make_sequence(this, x);
|
||||||
|
}
|
||||||
|
if (this.right instanceof AST_Sequence) {
|
||||||
|
if (this.left.has_side_effects(compressor)) return this;
|
||||||
|
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
|
||||||
|
var x = this.right.expressions;
|
||||||
|
var last = x.length - 1;
|
||||||
|
for (var i = 0; i < last; i++) {
|
||||||
|
if (!assign && x[i].has_side_effects(compressor)) break;
|
||||||
}
|
}
|
||||||
if (this.right instanceof AST_Sequence && !this.left.has_side_effects(compressor)) {
|
if (i == last) {
|
||||||
var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
|
x = x.slice();
|
||||||
var x = this.right.expressions;
|
var e = this.clone();
|
||||||
var last = x.length - 1;
|
e.right = x.pop();
|
||||||
for (var i = 0; i < last; i++) {
|
x.push(e);
|
||||||
if (!assign && x[i].has_side_effects(compressor)) break;
|
return make_sequence(this, x);
|
||||||
}
|
}
|
||||||
if (i == last) {
|
if (i > 0) {
|
||||||
x = x.slice();
|
var e = this.clone();
|
||||||
var e = this.clone();
|
e.right = make_sequence(this.right, x.slice(i));
|
||||||
e.right = x.pop();
|
x = x.slice(0, i);
|
||||||
x.push(e);
|
x.push(e);
|
||||||
return make_sequence(this, x).optimize(compressor);
|
return make_sequence(this, x);
|
||||||
} else if (i > 0) {
|
|
||||||
var e = this.clone();
|
|
||||||
e.right = make_sequence(this.right, x.slice(i));
|
|
||||||
x = x.slice(0, i);
|
|
||||||
x.push(e);
|
|
||||||
return make_sequence(this, x).optimize(compressor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@@ -6240,8 +6364,10 @@ merge(Compressor.prototype, {
|
|||||||
// result. hence, force switch.
|
// result. hence, force switch.
|
||||||
reverse();
|
reverse();
|
||||||
}
|
}
|
||||||
var seq = self.lift_sequences(compressor);
|
if (compressor.option("sequences")) {
|
||||||
if (seq !== self) return seq;
|
var seq = self.lift_sequences(compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
if (compressor.option("assignments") && lazy_op[self.operator]) {
|
if (compressor.option("assignments") && lazy_op[self.operator]) {
|
||||||
var assign = self.right;
|
var assign = self.right;
|
||||||
// a || (a = x) => a = a || x
|
// a || (a = x) => a = a || x
|
||||||
@@ -6450,7 +6576,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
// (x || false) && y => x ? y : false
|
// (x || false) && y => x ? y : false
|
||||||
if (self.left.operator == "||") {
|
if (self.left.operator == "||") {
|
||||||
var lr = self.left.right.tail_node().evaluate(compressor);
|
var lr = self.left.right.evaluate(compressor, true);
|
||||||
if (!lr) return make_node(AST_Conditional, self, {
|
if (!lr) return make_node(AST_Conditional, self, {
|
||||||
condition: self.left.left,
|
condition: self.left.left,
|
||||||
consequent: self.right,
|
consequent: self.right,
|
||||||
@@ -6484,7 +6610,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
// x && true || y => x ? true : y
|
// x && true || y => x ? true : y
|
||||||
if (self.left.operator == "&&") {
|
if (self.left.operator == "&&") {
|
||||||
var lr = self.left.right.is_truthy() || self.left.right.tail_node().evaluate(compressor);
|
var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true);
|
||||||
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
|
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
|
||||||
condition: self.left.left,
|
condition: self.left.left,
|
||||||
consequent: self.left.right,
|
consequent: self.left.right,
|
||||||
@@ -6831,7 +6957,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node.truthy) return true;
|
if (node.truthy) return true;
|
||||||
if (node.falsy) return false;
|
if (node.falsy) return false;
|
||||||
if (node.is_truthy()) return true;
|
if (node.is_truthy()) return true;
|
||||||
return node.evaluate(compressor);
|
return node.evaluate(compressor, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_indexFn(node) {
|
function is_indexFn(node) {
|
||||||
@@ -6953,9 +7079,9 @@ merge(Compressor.prototype, {
|
|||||||
var fn = node.fixed_value();
|
var fn = node.fixed_value();
|
||||||
if (!(fn instanceof AST_Lambda)) return;
|
if (!(fn instanceof AST_Lambda)) return;
|
||||||
if (!fn.name) return;
|
if (!fn.name) return;
|
||||||
var fn_def = fn.name.definition();
|
if (fn.name.definition() !== def) return;
|
||||||
if (fn_def.scope !== fn.name.scope) return;
|
if (def.scope !== fn.name.scope) return;
|
||||||
if (fixed.variables.get(fn.name.name) !== fn_def) return;
|
if (fixed.variables.get(fn.name.name) !== def) return;
|
||||||
fn.name = fn.name.clone();
|
fn.name = fn.name.clone();
|
||||||
var value_def = value.variables.get(fn.name.name) || value.def_function(fn.name);
|
var value_def = value.variables.get(fn.name.name) || value.def_function(fn.name);
|
||||||
node.thedef = value_def;
|
node.thedef = value_def;
|
||||||
@@ -7158,8 +7284,10 @@ merge(Compressor.prototype, {
|
|||||||
|| parent instanceof AST_UnaryPrefix);
|
|| parent instanceof AST_UnaryPrefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var seq = self.lift_sequences(compressor);
|
if (compressor.option("sequences")) {
|
||||||
if (seq !== self) return seq;
|
var seq = self.lift_sequences(compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
if (!compressor.option("assignments")) return self;
|
if (!compressor.option("assignments")) return self;
|
||||||
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
||||||
// x = expr1 OP expr2
|
// x = expr1 OP expr2
|
||||||
@@ -7581,16 +7709,14 @@ merge(Compressor.prototype, {
|
|||||||
value = value.fixed_value();
|
value = value.fixed_value();
|
||||||
}
|
}
|
||||||
if (!value) return false;
|
if (!value) return false;
|
||||||
return !(value instanceof AST_Lambda)
|
if (!(value instanceof AST_Lambda)) return true;
|
||||||
|| compressor.parent() instanceof AST_New
|
var parent = compressor.parent();
|
||||||
|| !value.contains_this();
|
if (parent.TYPE != "Call") return true;
|
||||||
|
if (parent.expression !== compressor.self()) return true;
|
||||||
|
return !value.contains_this();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPT(AST_Sub, function(self, compressor) {
|
OPT(AST_Sub, function(self, compressor) {
|
||||||
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
|
||||||
}
|
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
var prop = self.property;
|
var prop = self.property;
|
||||||
if (compressor.option("properties")) {
|
if (compressor.option("properties")) {
|
||||||
@@ -7661,6 +7787,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_lhs(compressor.self(), parent)) return self;
|
if (is_lhs(compressor.self(), parent)) return self;
|
||||||
|
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
if (key !== prop) {
|
if (key !== prop) {
|
||||||
var sub = self.flatten_object(property, compressor);
|
var sub = self.flatten_object(property, compressor);
|
||||||
if (sub) {
|
if (sub) {
|
||||||
@@ -7755,10 +7885,6 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor) {
|
OPT(AST_Dot, function(self, compressor) {
|
||||||
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
|
||||||
var seq = lift_sequence_in_expression(self, compressor);
|
|
||||||
if (seq !== self) return seq.optimize(compressor);
|
|
||||||
}
|
|
||||||
if (self.property == "arguments" || self.property == "caller") {
|
if (self.property == "arguments" || self.property == "caller") {
|
||||||
AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", {
|
AST_Node.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", {
|
||||||
prop: self.property,
|
prop: self.property,
|
||||||
@@ -7768,6 +7894,10 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (is_lhs(compressor.self(), compressor.parent())) return self;
|
if (is_lhs(compressor.self(), compressor.parent())) return self;
|
||||||
|
if (compressor.option("sequences") && compressor.parent().TYPE != "Call") {
|
||||||
|
var seq = lift_sequence_in_expression(self, compressor);
|
||||||
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
|
}
|
||||||
if (compressor.option("unsafe_proto")
|
if (compressor.option("unsafe_proto")
|
||||||
&& self.expression instanceof AST_Dot
|
&& self.expression instanceof AST_Dot
|
||||||
&& self.expression.property == "prototype") {
|
&& self.expression.property == "prototype") {
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ function minify(files, options) {
|
|||||||
if (!HOP(options.output, "code") || options.output.code) {
|
if (!HOP(options.output, "code") || options.output.code) {
|
||||||
if (options.sourceMap) {
|
if (options.sourceMap) {
|
||||||
options.output.source_map = SourceMap({
|
options.output.source_map = SourceMap({
|
||||||
|
content: options.sourceMap.includeSources,
|
||||||
file: options.sourceMap.filename,
|
file: options.sourceMap.filename,
|
||||||
orig: source_maps,
|
orig: source_maps,
|
||||||
root: options.sourceMap.root
|
root: options.sourceMap.root
|
||||||
@@ -211,10 +212,8 @@ function minify(files, options) {
|
|||||||
if (files instanceof AST_Toplevel) {
|
if (files instanceof AST_Toplevel) {
|
||||||
throw new Error("original source content unavailable");
|
throw new Error("original source content unavailable");
|
||||||
} else for (var name in files) if (HOP(files, name)) {
|
} else for (var name in files) if (HOP(files, name)) {
|
||||||
options.output.source_map.get().setSourceContent(name, files[name]);
|
options.output.source_map.setSourceContent(name, files[name]);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
options.output.source_map.get()._sourcesContents = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete options.output.ast;
|
delete options.output.ast;
|
||||||
|
|||||||
@@ -783,6 +783,8 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||||
var value = this.value;
|
var value = this.value;
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/115
|
||||||
|
// https://github.com/mishoo/UglifyJS2/pull/1009
|
||||||
if (value < 0 || /^0/.test(make_num(value))) {
|
if (value < 0 || /^0/.test(make_num(value))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1352,11 +1354,18 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_RegExp, function(self, output) {
|
DEFPRINT(AST_RegExp, function(self, output) {
|
||||||
var regexp = self.value;
|
var regexp = self.value;
|
||||||
var str = regexp.toString();
|
var str = regexp.toString();
|
||||||
|
var end = str.lastIndexOf("/");
|
||||||
if (regexp.raw_source) {
|
if (regexp.raw_source) {
|
||||||
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
str = "/" + regexp.raw_source + str.slice(end);
|
||||||
|
} else if (end == 1) {
|
||||||
|
str = "/(?:)" + str.slice(end);
|
||||||
|
} else if (str.indexOf("/", 1) < end) {
|
||||||
|
str = "/" + str.slice(1, end).replace(/\\\\|[^/]?\//g, function(match) {
|
||||||
|
return match[0] == "\\" ? match : match.slice(0, -1) + "\\/";
|
||||||
|
}) + str.slice(end);
|
||||||
}
|
}
|
||||||
output.print(output.to_utf8(str).replace(/\\(?:\0(?![0-9])|[^\0])/g, function(seq) {
|
output.print(output.to_utf8(str).replace(/\\(?:\0(?![0-9])|[^\0])/g, function(match) {
|
||||||
switch (seq[1]) {
|
switch (match[1]) {
|
||||||
case "\n": return "\\n";
|
case "\n": return "\\n";
|
||||||
case "\r": return "\\r";
|
case "\r": return "\\r";
|
||||||
case "\t": return "\t";
|
case "\t": return "\t";
|
||||||
@@ -1366,7 +1375,7 @@ function OutputStream(options) {
|
|||||||
case "\x0B": return "\v";
|
case "\x0B": return "\v";
|
||||||
case "\u2028": return "\\u2028";
|
case "\u2028": return "\\u2028";
|
||||||
case "\u2029": return "\\u2029";
|
case "\u2029": return "\\u2029";
|
||||||
default: return seq;
|
default: return match;
|
||||||
}
|
}
|
||||||
}).replace(/[\n\r\u2028\u2029]/g, function(c) {
|
}).replace(/[\n\r\u2028\u2029]/g, function(c) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|||||||
12
lib/parse.js
12
lib/parse.js
@@ -241,16 +241,16 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
if (signal_eof && !ch)
|
if (signal_eof && !ch)
|
||||||
throw EX_EOF;
|
throw EX_EOF;
|
||||||
if (NEWLINE_CHARS[ch]) {
|
if (NEWLINE_CHARS[ch]) {
|
||||||
S.newline_before = S.newline_before || !in_string;
|
|
||||||
++S.line;
|
|
||||||
S.col = 0;
|
S.col = 0;
|
||||||
if (!in_string && ch == "\r" && peek() == "\n") {
|
S.line++;
|
||||||
// treat a \r\n sequence as a single \n
|
if (!in_string) S.newline_before = true;
|
||||||
++S.pos;
|
if (ch == "\r" && peek() == "\n") {
|
||||||
|
// treat `\r\n` as `\n`
|
||||||
|
S.pos++;
|
||||||
ch = "\n";
|
ch = "\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
++S.col;
|
S.col++;
|
||||||
}
|
}
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|||||||
22
lib/scope.js
22
lib/scope.js
@@ -162,17 +162,22 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
|
||||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
|
||||||
s.uses_eval = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = self.def_global(node);
|
sym = self.def_global(node);
|
||||||
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
||||||
sym.scope.uses_arguments = true;
|
sym.scope.uses_arguments = true;
|
||||||
}
|
}
|
||||||
|
if (name == "eval") {
|
||||||
|
var parent = tw.parent();
|
||||||
|
if (parent.TYPE == "Call" && parent.expression === node) {
|
||||||
|
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||||
|
s.uses_eval = true;
|
||||||
|
}
|
||||||
|
} else if (sym.undeclared) {
|
||||||
|
self.uses_eval = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
node.thedef = sym;
|
node.thedef = sym;
|
||||||
node.reference(options);
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
@@ -219,7 +224,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
var redef;
|
var redef;
|
||||||
while (redef = new_def.redefined()) new_def = redef;
|
while (redef = new_def.redefined()) new_def = redef;
|
||||||
} else {
|
} else {
|
||||||
new_def = self.globals.get(name) || scope.def_variable(node);
|
new_def = self.globals.get(name);
|
||||||
|
}
|
||||||
|
if (new_def) {
|
||||||
|
new_def.orig.push(node);
|
||||||
|
} else {
|
||||||
|
new_def = scope.def_variable(node);
|
||||||
}
|
}
|
||||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||||
node.thedef = new_def;
|
node.thedef = new_def;
|
||||||
|
|||||||
170
lib/sourcemap.js
170
lib/sourcemap.js
@@ -43,62 +43,144 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// a small wrapper around fitzgen's source-map library
|
var vlq_char = characters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
||||||
|
var vlq_bits = vlq_char.reduce(function(map, ch, bits) {
|
||||||
|
map[ch] = bits;
|
||||||
|
return map;
|
||||||
|
}, Object.create(null));
|
||||||
|
|
||||||
|
function vlq_decode(indices, str) {
|
||||||
|
var value = 0;
|
||||||
|
var shift = 0;
|
||||||
|
for (var i = 0, j = 0; i < str.length; i++) {
|
||||||
|
var bits = vlq_bits[str[i]];
|
||||||
|
value += (bits & 31) << shift;
|
||||||
|
if (bits & 32) {
|
||||||
|
shift += 5;
|
||||||
|
} else {
|
||||||
|
indices[j++] += value & 1 ? 0x80000000 | -(value >> 1) : value >> 1;
|
||||||
|
value = shift = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
function vlq_encode(num) {
|
||||||
|
var result = "";
|
||||||
|
num = Math.abs(num) << 1 | num >>> 31;
|
||||||
|
do {
|
||||||
|
var bits = num & 31;
|
||||||
|
if (num >>>= 5) bits |= 32;
|
||||||
|
result += vlq_char[bits];
|
||||||
|
} while (num);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_array_map() {
|
||||||
|
var map = Object.create(null);
|
||||||
|
var array = [];
|
||||||
|
array.index = function(name) {
|
||||||
|
if (!HOP(map, name)) {
|
||||||
|
map[name] = array.length;
|
||||||
|
array.push(name);
|
||||||
|
}
|
||||||
|
return map[name];
|
||||||
|
};
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
function SourceMap(options) {
|
function SourceMap(options) {
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
|
content: false,
|
||||||
file: null,
|
file: null,
|
||||||
root: null,
|
root: null,
|
||||||
orig: null,
|
orig: null,
|
||||||
orig_line_diff: 0,
|
|
||||||
dest_line_diff: 0,
|
|
||||||
}, true);
|
}, true);
|
||||||
var generator = new MOZ_SourceMap.SourceMapGenerator({
|
var sources = create_array_map();
|
||||||
file: options.file,
|
var sources_content = options.content && Object.create(null);
|
||||||
sourceRoot: options.root
|
var names = create_array_map();
|
||||||
});
|
var mappings = "";
|
||||||
var maps = options.orig && Object.create(null);
|
if (options.orig) Object.keys(options.orig).forEach(function(name) {
|
||||||
if (maps) for (var source in options.orig) {
|
var map = options.orig[name];
|
||||||
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
|
var indices = [ 0, 0, 1, 0, 0 ];
|
||||||
if (Array.isArray(options.orig[source].sources)) {
|
map.mappings = map.mappings.split(/;/).map(function(line) {
|
||||||
map._sources.toArray().forEach(function(source) {
|
indices[0] = 0;
|
||||||
var sourceContent = map.sourceContentFor(source, true);
|
return line.split(/,/).map(function(segment) {
|
||||||
if (sourceContent) generator.setSourceContent(source, sourceContent);
|
return indices.slice(0, vlq_decode(indices, segment));
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
if (!sources_content || !map.sourcesContent) return;
|
||||||
|
for (var i = 0; i < map.sources.length; i++) {
|
||||||
|
var content = map.sourcesContent[i];
|
||||||
|
if (content) sources_content[map.sources[i]] = content;
|
||||||
}
|
}
|
||||||
maps[source] = map;
|
});
|
||||||
}
|
var generated_line = 1;
|
||||||
|
var generated_column = 0;
|
||||||
|
var source_index = 0;
|
||||||
|
var original_line = 1;
|
||||||
|
var original_column = 0;
|
||||||
|
var name_index = 0;
|
||||||
return {
|
return {
|
||||||
add: function(source, gen_line, gen_col, orig_line, orig_col, name) {
|
add: options.orig ? function(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||||
var map = maps && maps[source];
|
var map = options.orig[source];
|
||||||
if (map) {
|
if (map) {
|
||||||
var info = map.originalPositionFor({
|
var segments = map.mappings[orig_line - 1];
|
||||||
line: orig_line,
|
if (!segments) return;
|
||||||
column: orig_col
|
var indices;
|
||||||
});
|
for (var i = 0; i < segments.length; i++) {
|
||||||
if (info.source === null) return;
|
var col = segments[i][0];
|
||||||
source = info.source;
|
if (orig_col >= col) indices = segments[i];
|
||||||
orig_line = info.line;
|
if (orig_col <= col) break;
|
||||||
orig_col = info.column;
|
|
||||||
name = info.name || name;
|
|
||||||
}
|
|
||||||
generator.addMapping({
|
|
||||||
name: name,
|
|
||||||
source: source,
|
|
||||||
generated: {
|
|
||||||
line: gen_line + options.dest_line_diff,
|
|
||||||
column: gen_col
|
|
||||||
},
|
|
||||||
original: {
|
|
||||||
line: orig_line + options.orig_line_diff,
|
|
||||||
column: orig_col
|
|
||||||
}
|
}
|
||||||
});
|
if (!indices || indices.length < 4) return;
|
||||||
},
|
source = map.sources[indices[1]];
|
||||||
get: function() {
|
orig_line = indices[2];
|
||||||
return generator;
|
orig_col = indices[3];
|
||||||
},
|
if (indices.length > 4) name = map.names[indices[4]];
|
||||||
|
}
|
||||||
|
add(source, gen_line, gen_col, orig_line, orig_col, name);
|
||||||
|
} : add,
|
||||||
|
setSourceContent: sources_content ? function(source, content) {
|
||||||
|
sources_content[source] = content;
|
||||||
|
} : noop,
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return JSON.stringify(generator.toJSON());
|
return JSON.stringify({
|
||||||
|
version: 3,
|
||||||
|
file: options.file || undefined,
|
||||||
|
sourceRoot: options.root || undefined,
|
||||||
|
sources: sources,
|
||||||
|
sourcesContent: sources_content ? sources.map(function(source) {
|
||||||
|
return sources_content[source] || null;
|
||||||
|
}) : undefined,
|
||||||
|
names: names,
|
||||||
|
mappings: mappings,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||||
|
if (generated_line < gen_line) {
|
||||||
|
generated_column = 0;
|
||||||
|
do {
|
||||||
|
mappings += ";";
|
||||||
|
} while (++generated_line < gen_line);
|
||||||
|
} else if (mappings) {
|
||||||
|
mappings += ",";
|
||||||
|
}
|
||||||
|
mappings += vlq_encode(gen_col - generated_column);
|
||||||
|
generated_column = gen_col;
|
||||||
|
var src_idx = sources.index(source);
|
||||||
|
mappings += vlq_encode(src_idx - source_index);
|
||||||
|
source_index = src_idx;
|
||||||
|
mappings += vlq_encode(orig_line - original_line);
|
||||||
|
original_line = orig_line;
|
||||||
|
mappings += vlq_encode(orig_col - original_column);
|
||||||
|
original_column = orig_col;
|
||||||
|
if (name != null) {
|
||||||
|
var name_idx = names.index(name);
|
||||||
|
mappings += vlq_encode(name_idx - name_index);
|
||||||
|
name_index = name_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
|
|
||||||
(function(DEF) {
|
(function(DEF) {
|
||||||
function do_list(list, tw) {
|
function do_list(list, tw) {
|
||||||
return MAP(list, function(node) {
|
return List(list, function(node) {
|
||||||
return node.transform(tw, true);
|
return node.transform(tw, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
28
lib/utils.js
28
lib/utils.js
@@ -113,8 +113,8 @@ function return_true() { return true; }
|
|||||||
function return_this() { return this; }
|
function return_this() { return this; }
|
||||||
function return_null() { return null; }
|
function return_null() { return null; }
|
||||||
|
|
||||||
var MAP = (function() {
|
var List = (function() {
|
||||||
function MAP(a, f, backwards) {
|
function List(a, f, backwards) {
|
||||||
var ret = [], top = [], i;
|
var ret = [], top = [], i;
|
||||||
function doit() {
|
function doit() {
|
||||||
var val = f(a[i], i);
|
var val = f(a[i], i);
|
||||||
@@ -149,14 +149,14 @@ var MAP = (function() {
|
|||||||
}
|
}
|
||||||
return top.concat(ret);
|
return top.concat(ret);
|
||||||
}
|
}
|
||||||
MAP.at_top = function(val) { return new AtTop(val) };
|
List.at_top = function(val) { return new AtTop(val); };
|
||||||
MAP.splice = function(val) { return new Splice(val) };
|
List.splice = function(val) { return new Splice(val); };
|
||||||
MAP.last = function(val) { return new Last(val) };
|
List.last = function(val) { return new Last(val); };
|
||||||
var skip = MAP.skip = {};
|
var skip = List.skip = {};
|
||||||
function AtTop(val) { this.v = val }
|
function AtTop(val) { this.v = val; }
|
||||||
function Splice(val) { this.v = val }
|
function Splice(val) { this.v = val; }
|
||||||
function Last(val) { this.v = val }
|
function Last(val) { this.v = val; }
|
||||||
return MAP;
|
return List;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function push_uniq(array, el) {
|
function push_uniq(array, el) {
|
||||||
@@ -185,7 +185,7 @@ function makePredicate(words) {
|
|||||||
|
|
||||||
function all(array, predicate) {
|
function all(array, predicate) {
|
||||||
for (var i = array.length; --i >= 0;)
|
for (var i = array.length; --i >= 0;)
|
||||||
if (!predicate(array[i]))
|
if (!predicate(array[i], i))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -217,6 +217,12 @@ Dictionary.prototype = {
|
|||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
has: function(key) { return ("$" + key) in this._values },
|
has: function(key) { return ("$" + key) in this._values },
|
||||||
|
all: function(predicate) {
|
||||||
|
for (var i in this._values)
|
||||||
|
if (!predicate(this._values[i], i.substr(1)))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
each: function(f) {
|
each: function(f) {
|
||||||
for (var i in this._values)
|
for (var i in this._values)
|
||||||
f(this._values[i], i.substr(1));
|
f(this._values[i], i.substr(1));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.7.7",
|
"version": "3.9.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "~2.20.3",
|
"commander": "~2.20.3"
|
||||||
"source-map": "~0.6.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~7.1.0",
|
"acorn": "~7.1.0",
|
||||||
|
|||||||
@@ -207,8 +207,9 @@ function reminify(orig_options, input_code, input_formatted, stdout) {
|
|||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
var expected = stdout[options.toplevel ? 1 : 0];
|
var toplevel = sandbox.has_toplevel(options);
|
||||||
var actual = run_code(result.code, options.toplevel);
|
var expected = stdout[toplevel ? 1 : 0];
|
||||||
|
var actual = run_code(result.code, toplevel);
|
||||||
if (typeof expected != "string" && typeof actual != "string" && expected.name == actual.name) {
|
if (typeof expected != "string" && typeof actual != "string" && expected.name == actual.name) {
|
||||||
actual = expected;
|
actual = expected;
|
||||||
}
|
}
|
||||||
@@ -378,7 +379,10 @@ function test_case(test) {
|
|||||||
}
|
}
|
||||||
if (test.expect_stdout && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
if (test.expect_stdout && (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
||||||
var stdout = [ run_code(input_code), run_code(input_code, true) ];
|
var stdout = [ run_code(input_code), run_code(input_code, true) ];
|
||||||
var toplevel = test.options.toplevel;
|
var toplevel = sandbox.has_toplevel({
|
||||||
|
compress: test.options,
|
||||||
|
mangle: test.mangle
|
||||||
|
});
|
||||||
var actual = stdout[toplevel ? 1 : 0];
|
var actual = stdout[toplevel ? 1 : 0];
|
||||||
if (test.expect_stdout === true) {
|
if (test.expect_stdout === true) {
|
||||||
test.expect_stdout = actual;
|
test.expect_stdout = actual;
|
||||||
|
|||||||
@@ -7765,3 +7765,44 @@ issue_3700: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3744: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(a) {
|
||||||
|
({
|
||||||
|
get p() {
|
||||||
|
switch (1) {
|
||||||
|
case 0:
|
||||||
|
f((a = 2, 3));
|
||||||
|
case 1:
|
||||||
|
console.log(function g(b) {
|
||||||
|
return b || "PASS";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).p;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function f(a) {
|
||||||
|
({
|
||||||
|
get p() {
|
||||||
|
switch (1) {
|
||||||
|
case 0:
|
||||||
|
f();
|
||||||
|
case 1:
|
||||||
|
console.log(b || "PASS");
|
||||||
|
}
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
}).p;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1240,11 +1240,11 @@ issue_2535_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
y();
|
y();
|
||||||
x() && y();
|
x() && y();
|
||||||
(x(), 1) && y();
|
x(), y();
|
||||||
x() && y();
|
x() && y();
|
||||||
x() && y();
|
x() && y();
|
||||||
x() && y();
|
x() && y();
|
||||||
(x(), 0) && y();
|
x();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1191,10 +1191,10 @@ issue_2105_1: {
|
|||||||
input: {
|
input: {
|
||||||
!function(factory) {
|
!function(factory) {
|
||||||
factory();
|
factory();
|
||||||
}( function() {
|
}(function() {
|
||||||
return function(fn) {
|
return function(fn) {
|
||||||
fn()().prop();
|
fn()().prop();
|
||||||
}( function() {
|
}(function() {
|
||||||
function bar() {
|
function bar() {
|
||||||
var quux = function() {
|
var quux = function() {
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
@@ -1205,7 +1205,7 @@ issue_2105_1: {
|
|||||||
return { prop: foo };
|
return { prop: foo };
|
||||||
}
|
}
|
||||||
return bar;
|
return bar;
|
||||||
} );
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -1235,10 +1235,10 @@ issue_2105_2: {
|
|||||||
input: {
|
input: {
|
||||||
!function(factory) {
|
!function(factory) {
|
||||||
factory();
|
factory();
|
||||||
}( function() {
|
}(function() {
|
||||||
return function(fn) {
|
return function(fn) {
|
||||||
fn()().prop();
|
fn()().prop();
|
||||||
}( function() {
|
}(function() {
|
||||||
function bar() {
|
function bar() {
|
||||||
var quux = function() {
|
var quux = function() {
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
@@ -1249,7 +1249,7 @@ issue_2105_2: {
|
|||||||
return { prop: foo };
|
return { prop: foo };
|
||||||
}
|
}
|
||||||
return bar;
|
return bar;
|
||||||
} );
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -1258,6 +1258,44 @@ issue_2105_2: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2105_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(factory) {
|
||||||
|
factory();
|
||||||
|
}(function() {
|
||||||
|
return function(fn) {
|
||||||
|
fn()().prop();
|
||||||
|
}(function() {
|
||||||
|
function bar() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}, foo = function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
};
|
||||||
|
return { prop: foo };
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!void void {
|
||||||
|
prop: function() {
|
||||||
|
console.log;
|
||||||
|
void console.log("PASS");
|
||||||
|
}
|
||||||
|
}.prop();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
issue_2226_1: {
|
issue_2226_1: {
|
||||||
options = {
|
options = {
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -2330,7 +2368,7 @@ function_parameter_ie8: {
|
|||||||
(function() {
|
(function() {
|
||||||
(function f() {
|
(function f() {
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
})(0);
|
})();
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -2375,3 +2413,34 @@ issue_3673: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3746: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
A;
|
||||||
|
} catch (e) {
|
||||||
|
var e;
|
||||||
|
}
|
||||||
|
(function f(a) {
|
||||||
|
e = a;
|
||||||
|
})();
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
A;
|
||||||
|
} catch (e) {
|
||||||
|
var e;
|
||||||
|
}
|
||||||
|
(function(a) {
|
||||||
|
e = a;
|
||||||
|
})();
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2161,3 +2161,32 @@ collapse_vars_regexp: {
|
|||||||
"abbb",
|
"abbb",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3738: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(1 / (0 + ([] - 1) % 1));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1 / (0 + ([] - 1) % 1));
|
||||||
|
}
|
||||||
|
expect_stdout: "Infinity"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3755: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
unsafe_math: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log((/4/.exec(1 + (!0 - 5 / "23")) || 0).p);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((/4/.exec(!0 - 5 / "23" + 1), 0).p);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -342,11 +342,7 @@ inner_ref: {
|
|||||||
}(2));
|
}(2));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(a) {
|
console.log(1, void 0);
|
||||||
return a;
|
|
||||||
}(1), function(a) {
|
|
||||||
return a;
|
|
||||||
}());
|
|
||||||
}
|
}
|
||||||
expect_stdout: "1 undefined"
|
expect_stdout: "1 undefined"
|
||||||
}
|
}
|
||||||
@@ -1024,9 +1020,7 @@ issue_2616: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var c = "FAIL";
|
var c = "FAIL";
|
||||||
!function(NaN) {
|
(true << []) - NaN || (c = "PASS");
|
||||||
(true << NaN) - 0/0 || (c = "PASS");
|
|
||||||
}([]);
|
|
||||||
console.log(c);
|
console.log(c);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -1276,7 +1270,7 @@ issue_2630_3: {
|
|||||||
(function() {
|
(function() {
|
||||||
(function f1(a) {
|
(function f1(a) {
|
||||||
f2();
|
f2();
|
||||||
--x >= 0 && f1({});
|
--x >= 0 && f1();
|
||||||
})(a++);
|
})(a++);
|
||||||
function f2() {
|
function f2() {
|
||||||
a++;
|
a++;
|
||||||
@@ -1577,7 +1571,23 @@ issue_2663_3: {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicate_argnames: {
|
duplicate_argnames_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, a, a) {
|
||||||
|
return a;
|
||||||
|
}("FAIL", 42, "PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_argnames_2: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -1595,7 +1605,31 @@ duplicate_argnames: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "PASS";
|
var a = "PASS";
|
||||||
console, b && (a = "FAIL");
|
console, void 0 && (a = "FAIL");
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_argnames_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
function f(b, b, b) {
|
||||||
|
b && (a = "PASS");
|
||||||
|
}
|
||||||
|
f(null, 0, console, "42".toString());
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
b = console, "42".toString(), b && (a = "PASS");
|
||||||
var b;
|
var b;
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
@@ -1754,8 +1788,7 @@ inline_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(1);
|
console.log(1);
|
||||||
a = 2, console.log(a);
|
console.log(2);
|
||||||
var a;
|
|
||||||
(function(b) {
|
(function(b) {
|
||||||
var c = b;
|
var c = b;
|
||||||
console.log(c);
|
console.log(c);
|
||||||
@@ -1788,8 +1821,7 @@ inline_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(1);
|
console.log(1);
|
||||||
a = 2, console.log(a);
|
console.log(2);
|
||||||
var a;
|
|
||||||
b = 3, c = b, console.log(c);
|
b = 3, c = b, console.log(c);
|
||||||
var b, c;
|
var b, c;
|
||||||
}
|
}
|
||||||
@@ -1820,8 +1852,7 @@ inline_true: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(1);
|
console.log(1);
|
||||||
a = 2, console.log(a);
|
console.log(2);
|
||||||
var a;
|
|
||||||
b = 3, c = b, console.log(c);
|
b = 3, c = b, console.log(c);
|
||||||
var b, c;
|
var b, c;
|
||||||
}
|
}
|
||||||
@@ -1857,10 +1888,9 @@ use_before_init_in_loop: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicate_arg_var: {
|
duplicate_arg_var_1: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
toplevel: true,
|
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(function(b) {
|
console.log(function(b) {
|
||||||
@@ -1869,7 +1899,41 @@ duplicate_arg_var: {
|
|||||||
}("PASS"));
|
}("PASS"));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((b = "PASS", b));
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_arg_var_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(b) {
|
||||||
|
return b + "SS";
|
||||||
|
var b;
|
||||||
|
}("PA"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PA" + "SS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_arg_var_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(b) {
|
||||||
|
return b + "SS";
|
||||||
|
var b;
|
||||||
|
}("PA", "42".toString()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((b = "PA", "42".toString(), b + "SS"));
|
||||||
var b;
|
var b;
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -2017,10 +2081,8 @@ issue_3016_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
a = 3,
|
3[b];
|
||||||
a[b];
|
|
||||||
} while(0);
|
} while(0);
|
||||||
var a;
|
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
@@ -2528,10 +2590,9 @@ cross_references_2: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
hoist_props: true,
|
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 4,
|
passes: 6,
|
||||||
pure_getters: true,
|
properties: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
sequences: true,
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -3657,9 +3718,7 @@ pr_3595_3: {
|
|||||||
var g = [ "PASS" ];
|
var g = [ "PASS" ];
|
||||||
console.log(function(problem) {
|
console.log(function(problem) {
|
||||||
return g[problem];
|
return g[problem];
|
||||||
}(function(arg) {
|
}(g.indexOf("PASS")));
|
||||||
return g.indexOf(arg);
|
|
||||||
}("PASS")));
|
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
@@ -3785,3 +3844,221 @@ issue_3679_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preceding_side_effects: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, b, c) {
|
||||||
|
return b;
|
||||||
|
}(console, "PASS", 42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((console, 42, "PASS"));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
trailing_side_effects: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, b, c) {
|
||||||
|
return b;
|
||||||
|
}(42, "PASS", console));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a, b, c) {
|
||||||
|
return b;
|
||||||
|
}(42, "PASS", console));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
preserve_binding_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return this === o ? "FAIL" : "PASS";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(o.f)());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return this === o ? "FAIL" : "PASS";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log((0, o.f)());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
preserve_binding_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return this === o ? "FAIL" : "PASS";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(o.f)());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
f: function() {
|
||||||
|
return this === o ? "FAIL" : "PASS";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log((0, o.f)());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3770: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
function f(a, a) {
|
||||||
|
var b = function() {
|
||||||
|
return a || "PASS";
|
||||||
|
}();
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
f("FAIL");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
b = a || "PASS",
|
||||||
|
console.log(b);
|
||||||
|
var a, b;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3771: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
function f(a) {
|
||||||
|
var a = f(1234);
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
(function f(a) {
|
||||||
|
f();
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3772: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
dead_code: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
var b = f();
|
||||||
|
function g() {
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
g();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3777_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
ff && ff(NaN);
|
||||||
|
function ff(a) {
|
||||||
|
var a = console.log("PASS");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
ff && ff(NaN);
|
||||||
|
function ff(a) {
|
||||||
|
var a = console.log("PASS");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3777_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
ff(ff.p);
|
||||||
|
function ff(a) {
|
||||||
|
var a = console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
ff(ff.p);
|
||||||
|
function ff(a) {
|
||||||
|
var a = console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2361,3 +2361,62 @@ issue_3542: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3703: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
function f() {
|
||||||
|
var b;
|
||||||
|
function g() {
|
||||||
|
a = "FAIL";
|
||||||
|
}
|
||||||
|
var c = g;
|
||||||
|
function h() {
|
||||||
|
f;
|
||||||
|
}
|
||||||
|
a ? b |= c : b.p;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
(function() {
|
||||||
|
var b;
|
||||||
|
var c = function g() {
|
||||||
|
a = "FAIL";
|
||||||
|
};
|
||||||
|
a ? b |= c : b.p;
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3750: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
return function a() {
|
||||||
|
return a && console.log("PASS");
|
||||||
|
}();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
return function a() {
|
||||||
|
return a && console.log("PASS");
|
||||||
|
}();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ warn: {
|
|||||||
}().length);
|
}().length);
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
|
|
||||||
"WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
"WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
||||||
|
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
128
test/compress/issue-3768.js
Normal file
128
test/compress/issue-3768.js
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
mangle: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var e = eval, x = 42;
|
||||||
|
(function() {
|
||||||
|
console.log(e("typeof x"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var e = eval, x = 42;
|
||||||
|
(function() {
|
||||||
|
console.log(e("typeof x"));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
compress: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 42;
|
||||||
|
return eval("typeof a");
|
||||||
|
}(), function(e) {
|
||||||
|
var a = null;
|
||||||
|
return e("typeof a");
|
||||||
|
}(eval), function(eval) {
|
||||||
|
var a = false;
|
||||||
|
return eval("typeof a");
|
||||||
|
}(eval), function(f) {
|
||||||
|
var a = "STRING";
|
||||||
|
var eval = f;
|
||||||
|
return eval("typeof a");
|
||||||
|
}(eval), function(g) {
|
||||||
|
var a = eval;
|
||||||
|
function eval() {
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
return eval()("typeof a");
|
||||||
|
}(eval));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 42;
|
||||||
|
return eval("typeof a");
|
||||||
|
}(), (0, eval)("typeof a"), function(eval) {
|
||||||
|
var a = false;
|
||||||
|
return eval("typeof a");
|
||||||
|
}(eval), function(f) {
|
||||||
|
var a = "STRING";
|
||||||
|
var eval = f;
|
||||||
|
return eval("typeof a");
|
||||||
|
}(eval), function(g) {
|
||||||
|
var a = eval;
|
||||||
|
function eval() {
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
return eval()("typeof a");
|
||||||
|
}(eval));
|
||||||
|
}
|
||||||
|
expect_stdout: "number undefined boolean string undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_arg_1: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var z = "foo";
|
||||||
|
(function() {
|
||||||
|
var z = false;
|
||||||
|
(function(e) {
|
||||||
|
var z = 42;
|
||||||
|
e("console.log(typeof z)");
|
||||||
|
})(eval);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var z = "foo";
|
||||||
|
(function() {
|
||||||
|
var o = false;
|
||||||
|
(function(o) {
|
||||||
|
var a = 42;
|
||||||
|
o("console.log(typeof z)");
|
||||||
|
})(eval);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
call_arg_2: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function eval() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
var z = "foo";
|
||||||
|
(function() {
|
||||||
|
var z = false;
|
||||||
|
(function(e) {
|
||||||
|
var z = 42;
|
||||||
|
e("console.log(typeof z)");
|
||||||
|
})(eval);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function n() {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
var o = "foo";
|
||||||
|
(function() {
|
||||||
|
var o = false;
|
||||||
|
(function(o) {
|
||||||
|
var n = 42;
|
||||||
|
o("console.log(typeof z)");
|
||||||
|
})(n);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
@@ -16,7 +16,6 @@ wrongly_optimized: {
|
|||||||
function func() {
|
function func() {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
// TODO: optimize to `func(), bar()`
|
func(), 1, bar();
|
||||||
(func(), 1) && bar();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ wrongly_optimized: {
|
|||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
expression: true,
|
expression: true,
|
||||||
}
|
}
|
||||||
@@ -99,8 +100,8 @@ wrongly_optimized: {
|
|||||||
function func() {
|
function func() {
|
||||||
foo();
|
foo();
|
||||||
}
|
}
|
||||||
// TODO: optimize to `func(), bar()`
|
func(), 1;
|
||||||
if (func(), 1) bar();
|
bar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ remove_sequence: {
|
|||||||
(0, 1, _decorators.logThis)();
|
(0, 1, _decorators.logThis)();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
eval();
|
(0, eval)();
|
||||||
logThis();
|
logThis();
|
||||||
(0, _decorators.logThis)();
|
(0, _decorators.logThis)();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,20 +53,23 @@ this_binding_conditionals: {
|
|||||||
this_binding_collapse_vars: {
|
this_binding_collapse_vars: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: true,
|
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
"use strict";
|
function f() {
|
||||||
var c = a; c();
|
"use strict";
|
||||||
var d = a.b; d();
|
var c = a; c();
|
||||||
var e = eval; e();
|
var d = a.b; d();
|
||||||
|
var e = eval; e();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
"use strict";
|
function f() {
|
||||||
a();
|
"use strict";
|
||||||
(0, a.b)();
|
a();
|
||||||
(0, eval)();
|
(0, a.b)();
|
||||||
|
(0, eval)();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +100,7 @@ this_binding_side_effects: {
|
|||||||
(function(foo) {
|
(function(foo) {
|
||||||
foo();
|
foo();
|
||||||
(0, foo.bar)();
|
(0, foo.bar)();
|
||||||
eval("console.log(foo);");
|
(0, eval)("console.log(foo);");
|
||||||
}());
|
}());
|
||||||
(function(foo) {
|
(function(foo) {
|
||||||
"use strict";
|
"use strict";
|
||||||
@@ -144,7 +147,7 @@ this_binding_sequences: {
|
|||||||
return eval("this");
|
return eval("this");
|
||||||
}()),
|
}()),
|
||||||
console.log(typeof function() {
|
console.log(typeof function() {
|
||||||
return eval("this");
|
return (0, eval)("this");
|
||||||
}()),
|
}()),
|
||||||
console.log(typeof function() {
|
console.log(typeof function() {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|||||||
@@ -728,7 +728,7 @@ issue_2630_3: {
|
|||||||
(function() {
|
(function() {
|
||||||
(function f1() {
|
(function f1() {
|
||||||
f2();
|
f2();
|
||||||
--x >= 0 && f1({});
|
--x >= 0 && f1();
|
||||||
})(a++);
|
})(a++);
|
||||||
function f2() {
|
function f2() {
|
||||||
a++;
|
a++;
|
||||||
@@ -1369,7 +1369,7 @@ recursive_iife_1: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function f(a, b) {
|
console.log(function f(a, b) {
|
||||||
return b || f("FAIL", "PASS");
|
return b || f(0, "PASS");
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -1388,7 +1388,7 @@ recursive_iife_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function f(a, b) {
|
console.log(function f(a, b) {
|
||||||
return b || f("FAIL", "PASS");
|
return b || f(0, "PASS");
|
||||||
}(0, 0));
|
}(0, 0));
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -1416,7 +1416,7 @@ recursive_iife_3: {
|
|||||||
var a = 1, c = "PASS";
|
var a = 1, c = "PASS";
|
||||||
(function() {
|
(function() {
|
||||||
(function f(b, d, e) {
|
(function f(b, d, e) {
|
||||||
a-- && f(null, 42, 0);
|
a-- && f(0, 42, 0);
|
||||||
e && (c = "FAIL");
|
e && (c = "FAIL");
|
||||||
d && d.p;
|
d && d.p;
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -817,6 +817,29 @@ issue_2208_5: {
|
|||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2208_6: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a = 42;
|
||||||
|
console.log(("FAIL", {
|
||||||
|
p: function() {
|
||||||
|
return this.a;
|
||||||
|
}
|
||||||
|
}.p)());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = 42;
|
||||||
|
console.log(function() {
|
||||||
|
return this.a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
issue_2256: {
|
issue_2256: {
|
||||||
options = {
|
options = {
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
|
|||||||
@@ -2071,13 +2071,8 @@ issue_1670_6: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function(a) {
|
(function(a) {
|
||||||
switch (1) {
|
a = 1;
|
||||||
case a = 1:
|
console.log(a);
|
||||||
console.log(a);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log(2);
|
|
||||||
}
|
|
||||||
})(1);
|
})(1);
|
||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
@@ -2294,11 +2289,10 @@ redefine_farg_2: {
|
|||||||
console.log(f([]), g([]), h([]));
|
console.log(f([]), g([]), h([]));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log((a = [], typeof a), "number",function(a, b) {
|
console.log(typeof [], "number",function(a, b) {
|
||||||
a = b;
|
a = b;
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}([]));
|
}([]));
|
||||||
var a;
|
|
||||||
}
|
}
|
||||||
expect_stdout: "object number undefined"
|
expect_stdout: "object number undefined"
|
||||||
}
|
}
|
||||||
@@ -6516,17 +6510,17 @@ issue_3240_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
(function() {
|
||||||
(function f(b) {
|
f();
|
||||||
|
function f(b) {
|
||||||
if (!f.a) f.a = 0;
|
if (!f.a) f.a = 0;
|
||||||
console.log(f.a.toString());
|
console.log(f.a.toString());
|
||||||
var g = function() {
|
(function() {
|
||||||
(b ? function() {} : function() {
|
(b ? function() {} : function() {
|
||||||
f.a++;
|
f.a++;
|
||||||
f(1);
|
f(1);
|
||||||
})();
|
})();
|
||||||
};
|
})();
|
||||||
g();
|
}
|
||||||
})();
|
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -6560,7 +6554,8 @@ issue_3240_4: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
(function() {
|
||||||
(function f(b) {
|
f();
|
||||||
|
function f(b) {
|
||||||
if (!f.a) f.a = 0;
|
if (!f.a) f.a = 0;
|
||||||
console.log(f.a.toString());
|
console.log(f.a.toString());
|
||||||
(function() {
|
(function() {
|
||||||
@@ -6569,7 +6564,7 @@ issue_3240_4: {
|
|||||||
f(1);
|
f(1);
|
||||||
})();
|
})();
|
||||||
})();
|
})();
|
||||||
})();
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -6878,3 +6873,42 @@ issue_3666: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS PASS"
|
expect_stdout: "PASS PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3774: {
|
||||||
|
options = {
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var f = function() {
|
||||||
|
function g() {
|
||||||
|
if (!g.p) {
|
||||||
|
g.p = 1;
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return function() {
|
||||||
|
g();
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
f();
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var f = function() {
|
||||||
|
function g() {
|
||||||
|
if (!g.p) {
|
||||||
|
g.p = 1;
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return function() {
|
||||||
|
g();
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
f();
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -186,3 +186,290 @@ issue_3434_3: {
|
|||||||
/\nfo\n[\n]o\bbb/;
|
/\nfo\n[\n]o\bbb/;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3434_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
[
|
||||||
|
[ "", RegExp("") ],
|
||||||
|
[ "/", RegExp("/") ],
|
||||||
|
[ "//", RegExp("//") ],
|
||||||
|
[ "\/", RegExp("\\/") ],
|
||||||
|
[ "///", RegExp("///") ],
|
||||||
|
[ "/\/", RegExp("/\\/") ],
|
||||||
|
[ "\//", RegExp("\\//") ],
|
||||||
|
[ "\\/", RegExp("\\\\/") ],
|
||||||
|
[ "////", RegExp("////") ],
|
||||||
|
[ "//\/", RegExp("//\\/") ],
|
||||||
|
[ "/\//", RegExp("/\\//") ],
|
||||||
|
[ "/\\/", RegExp("/\\\\/") ],
|
||||||
|
[ "\///", RegExp("\\///") ],
|
||||||
|
[ "\/\/", RegExp("\\/\\/") ],
|
||||||
|
[ "\\//", RegExp("\\\\//") ],
|
||||||
|
[ "\\\/", RegExp("\\\\\\/") ],
|
||||||
|
].forEach(function(test) {
|
||||||
|
console.log(test[1].test("\\"), test[1].test(test[0]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
[
|
||||||
|
[ "", /(?:)/ ],
|
||||||
|
[ "/", /\// ],
|
||||||
|
[ "//", /\/\// ],
|
||||||
|
[ "/", /\// ],
|
||||||
|
[ "///", /\/\/\// ],
|
||||||
|
[ "//", /\/\// ],
|
||||||
|
[ "//", /\/\// ],
|
||||||
|
[ "\\/", /\\\// ],
|
||||||
|
[ "////", /\/\/\/\// ],
|
||||||
|
[ "///", /\/\/\// ],
|
||||||
|
[ "///", /\/\/\// ],
|
||||||
|
[ "/\\/", /\/\\\// ],
|
||||||
|
[ "///", /\/\/\// ],
|
||||||
|
[ "//", /\/\// ],
|
||||||
|
[ "\\//", /\\\/\// ],
|
||||||
|
[ "\\/", /\\\// ],
|
||||||
|
].forEach(function(test) {
|
||||||
|
console.log(test[1].test("\\"), test[1].test(test[0]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"true true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
"false true",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
exec: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (/a/.exec("AAA"))
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (;null;)
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_global: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (/a/g.exec("AAA"))
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (;null;)
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
test: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (/a/.test("AAA"))
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
while (false)
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_global: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (/a/g.test("AAA"))
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
while (false)
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
var_exec: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var r = /a/;
|
||||||
|
while (r.exec("AAA"))
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var r = /a/;
|
||||||
|
for (;null;)
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
var_exec_global: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
loops: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var r = /a/g;
|
||||||
|
while (r.exec("aaa"))
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var r = /a/g;
|
||||||
|
for (;r.exec("aaa");)
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
var_test: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var r = /a/;
|
||||||
|
while (r.test("AAA"))
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var r = /a/;
|
||||||
|
while (false)
|
||||||
|
console.log("FAIL");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
var_test_global: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var r = /a/g;
|
||||||
|
while (r.test("aaa"))
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var r = /a/g;
|
||||||
|
while (r.test("aaa"))
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_boolean: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/b/.exec({}) && console.log("PASS");
|
||||||
|
/b/.test({}) && console.log("PASS");
|
||||||
|
/b/g.exec({}) && console.log("PASS");
|
||||||
|
/b/g.test({}) && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
console.log("PASS");
|
||||||
|
console.log("PASS");
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_state_between_evaluate: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
for (var a in /[abc4]/g.exec("a"))
|
||||||
|
return "PASS";
|
||||||
|
return "FAIL";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
for (var a in /[abc4]/g.exec("a"))
|
||||||
|
return "PASS";
|
||||||
|
return "FAIL";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1093,3 +1093,22 @@ issue_3490_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS 42"
|
expect_stdout: "PASS 42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3703: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
sequences: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
while ((a = "PASS", 0).foo = 0);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
while (a = "PASS", (0).foo = 0);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
exports["Compressor"] = Compressor;
|
exports["Compressor"] = Compressor;
|
||||||
exports["defaults"] = defaults;
|
exports["defaults"] = defaults;
|
||||||
exports["JS_Parse_Error"] = JS_Parse_Error;
|
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||||
|
exports["List"] = List;
|
||||||
exports["mangle_properties"] = mangle_properties;
|
exports["mangle_properties"] = mangle_properties;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["OutputStream"] = OutputStream;
|
exports["OutputStream"] = OutputStream;
|
||||||
@@ -12,3 +13,4 @@ exports["to_ascii"] = to_ascii;
|
|||||||
exports["tokenizer"] = tokenizer;
|
exports["tokenizer"] = tokenizer;
|
||||||
exports["TreeTransformer"] = TreeTransformer;
|
exports["TreeTransformer"] = TreeTransformer;
|
||||||
exports["TreeWalker"] = TreeWalker;
|
exports["TreeWalker"] = TreeWalker;
|
||||||
|
exports["vlq_decode"] = vlq_decode;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z)));
|
function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z)));
|
||||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiYXJyIl0sIm1hcHBpbmdzIjoiMEpBQWNBLEtBQVFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3Qge2Zvb30gPSByZXF1aXJlKFwiYmFyXCIpO1xuY29uc3Qge2hlbGxvfSA9IHJlcXVpcmUoXCJ3b3JsZFwiKTtcblxuZm9vLngoLi4uZm9vLnkoaGVsbG8ueikpO1xuIl19
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCB7Zm9vfSA9IHJlcXVpcmUoXCJiYXJcIik7XG5jb25zdCB7aGVsbG99ID0gcmVxdWlyZShcIndvcmxkXCIpO1xuXG5mb28ueCguLi5mb28ueShoZWxsby56KSk7XG4iXSwibmFtZXMiOlsicmVxdWlyZSIsImFyciJdLCJtYXBwaW5ncyI6IjBKQUFjQSxLQUFRQyJ9
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
new function(){console.log(3)};
|
new function(){console.log(3)};
|
||||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
new function(){console.log(3)};
|
new function(){console.log(3)};
|
||||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9
|
||||||
|
|||||||
9
test/input/reduce/label.js
Normal file
9
test/input/reduce/label.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
var o = this;
|
||||||
|
|
||||||
|
for (var k in o) L17060: {
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var a;
|
||||||
|
|
||||||
|
console.log(k);
|
||||||
15
test/input/reduce/label.reduced.js
Normal file
15
test/input/reduce/label.reduced.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// (beautified)
|
||||||
|
var o = this;
|
||||||
|
|
||||||
|
for (var k in o) {}
|
||||||
|
|
||||||
|
var a;
|
||||||
|
|
||||||
|
console.log(k);
|
||||||
|
// output: a
|
||||||
|
//
|
||||||
|
// minify: k
|
||||||
|
//
|
||||||
|
// options: {
|
||||||
|
// "mangle": false
|
||||||
|
// }
|
||||||
8
test/input/reduce/setter.js
Normal file
8
test/input/reduce/setter.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
console.log(function f(a) {
|
||||||
|
({
|
||||||
|
set p(v) {
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
20
test/input/reduce/setter.reduced.js
Normal file
20
test/input/reduce/setter.reduced.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// (beautified)
|
||||||
|
console.log(function f(a) {
|
||||||
|
({
|
||||||
|
set p(v) {
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
// output: 1
|
||||||
|
//
|
||||||
|
// minify: 0
|
||||||
|
//
|
||||||
|
// options: {
|
||||||
|
// "compress": {
|
||||||
|
// "keep_fargs": false,
|
||||||
|
// "unsafe": true
|
||||||
|
// },
|
||||||
|
// "mangle": false
|
||||||
|
// }
|
||||||
18
test/input/reduce/unsafe_math.js
Normal file
18
test/input/reduce/unsafe_math.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
var _calls_ = 10, a = 100, b = 10, c = 0;
|
||||||
|
|
||||||
|
function f0(b_1, a, undefined_2) {
|
||||||
|
a++ + ++b;
|
||||||
|
{
|
||||||
|
var expr2 = (b + 1 - .1 - .1 - .1 || a || 3).toString();
|
||||||
|
L20778: for (var key2 in expr2) {
|
||||||
|
(c = c + 1) + [ --b + b_1, typeof f0 == "function" && --_calls_ >= 0 && f0(--b + typeof (undefined_2 = 1 === 1 ? a : b), --b + {
|
||||||
|
c: (c = c + 1) + null
|
||||||
|
}, a++ + (typeof f0 == "function" && --_calls_ >= 0 && f0(typeof (c = 1 + c, 3 / "a" * ("c" >>> 23..toString()) >= (b_1 && (b_1[(c = c + 1) + a--] = (- -0,
|
||||||
|
true + {})))), 3, 25))), 1 === 1 ? a : b ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var a_1 = f0([ , 0 ].length === 2);
|
||||||
|
|
||||||
|
console.log(null, a, b, c, Infinity, NaN, undefined);
|
||||||
20
test/input/reduce/unsafe_math.reduced.js
Normal file
20
test/input/reduce/unsafe_math.reduced.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// (beautified)
|
||||||
|
var b = 0;
|
||||||
|
|
||||||
|
var expr2 = (0 - 1 - .1 - .1).toString();
|
||||||
|
|
||||||
|
for (var key2 in expr2) {
|
||||||
|
--b;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(b);
|
||||||
|
// output: -19
|
||||||
|
//
|
||||||
|
// minify: -4
|
||||||
|
//
|
||||||
|
// options: {
|
||||||
|
// "compress": {
|
||||||
|
// "unsafe_math": true
|
||||||
|
// },
|
||||||
|
// "mangle": false
|
||||||
|
// }
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
function f(x) {
|
function f(x) {
|
||||||
return g(x);
|
return g(x);
|
||||||
function g(x) {
|
function g(x) {
|
||||||
return x;
|
return x + x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, [
|
assert.strictEqual(stdout, [
|
||||||
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
|
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
|
||||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUFBLE1BQWdCQyxRQUFRQyxJQUFJLEVBQUUsSUFBTyxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
|
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUVBLE1BQWNDLFFBQVFDLElBQUksRUFBRSxJQUFPLElBQUlGLElDQW5ELElBQUlHLElBQU0sV0FDTixTQUFTQyxJQUFLRCxLQUNWLE9BQU9BLElBR1gsT0FBT0MsSUFMRCJ9",
|
||||||
"",
|
"",
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
var stderrLines = stderr.split("\n");
|
var stderrLines = stderr.split("\n");
|
||||||
@@ -587,7 +587,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function read_map() {
|
function read_map() {
|
||||||
var map = JSON.parse(read("./test/input/issue-1236/simple.js.map"));
|
var map = JSON.parse(read("test/input/issue-1236/simple.js.map"));
|
||||||
delete map.sourcesContent;
|
delete map.sourcesContent;
|
||||||
return JSON.stringify(map).replace(/"/g, '\\"');
|
return JSON.stringify(map).replace(/"/g, '\\"');
|
||||||
}
|
}
|
||||||
@@ -674,7 +674,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
var command = uglifyjscmd + " test/input/rename/input.js --rename";
|
var command = uglifyjscmd + " test/input/rename/input.js --rename";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c}}\n");
|
assert.strictEqual(stdout, "function f(a){return b(a);function b(c){return c+c}}\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -682,7 +682,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename";
|
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n");
|
assert.strictEqual(stdout, "function f(n){return function(n){return n+n}(n)}\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -690,7 +690,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2";
|
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(n){return n}\n");
|
assert.strictEqual(stdout, "function f(n){return n+n}\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -698,7 +698,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
var command = uglifyjscmd + " test/input/rename/input.js -c passes=2";
|
var command = uglifyjscmd + " test/input/rename/input.js -c passes=2";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n");
|
assert.strictEqual(stdout, "function f(x){return function(x){return x+x}(x)}\n");
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ describe("minify", function() {
|
|||||||
"var a=n(3),b=r(12);",
|
"var a=n(3),b=r(12);",
|
||||||
'c("qux",a,b),o(11);',
|
'c("qux",a,b),o(11);',
|
||||||
].join(""));
|
].join(""));
|
||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should work with nameCache", function() {
|
it("Should work with nameCache", function() {
|
||||||
@@ -84,7 +84,7 @@ describe("minify", function() {
|
|||||||
"var a=n(3),b=r(12);",
|
"var a=n(3),b=r(12);",
|
||||||
'c("qux",a,b),o(11);',
|
'c("qux",a,b),o(11);',
|
||||||
].join(""));
|
].join(""));
|
||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should avoid cached names when mangling top-level variables", function() {
|
it("Should avoid cached names when mangling top-level variables", function() {
|
||||||
@@ -113,7 +113,7 @@ describe("minify", function() {
|
|||||||
'"xxyyy";var y={y:2,a:3},a=4;',
|
'"xxyyy";var y={y:2,a:3},a=4;',
|
||||||
'console.log(x.x,y.y,y.a,a);',
|
'console.log(x.x,y.y,y.a,a);',
|
||||||
].join(""));
|
].join(""));
|
||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should avoid cached names when mangling inner-scoped variables", function() {
|
it("Should avoid cached names when mangling inner-scoped variables", function() {
|
||||||
@@ -137,7 +137,7 @@ describe("minify", function() {
|
|||||||
'var o=function(o,n){console.log("extend");o();n()};function n(){console.log("A")}',
|
'var o=function(o,n){console.log("extend");o();n()};function n(){console.log("A")}',
|
||||||
'var e=function(n){function e(){console.log("B")}o(e,n);return e}(n);',
|
'var e=function(n){function e(){console.log("B")}o(e,n);return e}(n);',
|
||||||
].join(""));
|
].join(""));
|
||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed, true), run_code(original, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not parse invalid use of reserved words", function() {
|
it("Should not parse invalid use of reserved words", function() {
|
||||||
|
|||||||
249
test/mocha/reduce.js
Normal file
249
test/mocha/reduce.js
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var exec = require("child_process").exec;
|
||||||
|
var fs = require("fs");
|
||||||
|
var reduce_test = require("../reduce");
|
||||||
|
var semver = require("semver");
|
||||||
|
|
||||||
|
function read(path) {
|
||||||
|
return fs.readFileSync(path, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("test/reduce.js", function() {
|
||||||
|
this.timeout(60000);
|
||||||
|
it("Should reduce test case", function() {
|
||||||
|
var result = reduce_test(read("test/input/reduce/unsafe_math.js"), {
|
||||||
|
compress: {
|
||||||
|
unsafe_math: true,
|
||||||
|
},
|
||||||
|
mangle: false,
|
||||||
|
}, {
|
||||||
|
verbose: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, read("test/input/reduce/unsafe_math.reduced.js"));
|
||||||
|
});
|
||||||
|
it("Should eliminate unreferenced labels", function() {
|
||||||
|
var result = reduce_test(read("test/input/reduce/label.js"), {
|
||||||
|
mangle: false,
|
||||||
|
}, {
|
||||||
|
verbose: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, read("test/input/reduce/label.reduced.js"));
|
||||||
|
});
|
||||||
|
it("Should retain setter arguments", function() {
|
||||||
|
var result = reduce_test(read("test/input/reduce/setter.js"), {
|
||||||
|
compress: {
|
||||||
|
keep_fargs: false,
|
||||||
|
unsafe: true,
|
||||||
|
},
|
||||||
|
mangle: false,
|
||||||
|
}, {
|
||||||
|
verbose: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, read("test/input/reduce/setter.reduced.js"));
|
||||||
|
});
|
||||||
|
it("Should handle test cases with --toplevel", function() {
|
||||||
|
var result = reduce_test([
|
||||||
|
"var Infinity = 42;",
|
||||||
|
"console.log(Infinity);",
|
||||||
|
].join("\n"), {
|
||||||
|
toplevel: true,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// Can't reproduce test failure",
|
||||||
|
"// minify options: {",
|
||||||
|
'// "toplevel": true',
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should handle test cases with --compress toplevel", function() {
|
||||||
|
var result = reduce_test([
|
||||||
|
"var NaN = 42;",
|
||||||
|
"console.log(NaN);",
|
||||||
|
].join("\n"), {
|
||||||
|
compress: {
|
||||||
|
toplevel: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// Can't reproduce test failure",
|
||||||
|
"// minify options: {",
|
||||||
|
'// "compress": {',
|
||||||
|
'// "toplevel": true',
|
||||||
|
"// }",
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should handle test cases with --mangle toplevel", function() {
|
||||||
|
var result = reduce_test([
|
||||||
|
"var undefined = 42;",
|
||||||
|
"console.log(undefined);",
|
||||||
|
].join("\n"), {
|
||||||
|
mangle: {
|
||||||
|
toplevel: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// Can't reproduce test failure",
|
||||||
|
"// minify options: {",
|
||||||
|
'// "mangle": {',
|
||||||
|
'// "toplevel": true',
|
||||||
|
"// }",
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should handle test result of NaN", function() {
|
||||||
|
var result = reduce_test("throw 0 / 0;");
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// Can't reproduce test failure",
|
||||||
|
"// minify options: {}",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should print correct output for irreducible test case", function() {
|
||||||
|
var result = reduce_test([
|
||||||
|
"console.log(function f(a) {",
|
||||||
|
" return f.length;",
|
||||||
|
"}());",
|
||||||
|
].join("\n"), {
|
||||||
|
compress: {
|
||||||
|
keep_fargs: false,
|
||||||
|
},
|
||||||
|
mangle: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// (beautified)",
|
||||||
|
"console.log(function f(a) {",
|
||||||
|
" return f.length;",
|
||||||
|
"}());",
|
||||||
|
"// output: 1",
|
||||||
|
"// ",
|
||||||
|
"// minify: 0",
|
||||||
|
"// ",
|
||||||
|
"// options: {",
|
||||||
|
'// "compress": {',
|
||||||
|
'// "keep_fargs": false',
|
||||||
|
"// },",
|
||||||
|
'// "mangle": false',
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should fail when invalid option is supplied", function() {
|
||||||
|
var result = reduce_test("", {
|
||||||
|
compress: {
|
||||||
|
unsafe_regex: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
var err = result.error;
|
||||||
|
assert.ok(err instanceof Error);
|
||||||
|
assert.strictEqual(err.stack.split(/\n/)[0], "DefaultsError: `unsafe_regex` is not a supported option");
|
||||||
|
});
|
||||||
|
it("Should report on test case with invalid syntax", function() {
|
||||||
|
var result = reduce_test("var 0 = 1;");
|
||||||
|
var err = result.error;
|
||||||
|
assert.ok(err instanceof Error);
|
||||||
|
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Name expected");
|
||||||
|
});
|
||||||
|
it("Should format multi-line output correctly", function() {
|
||||||
|
var code = [
|
||||||
|
"var a = 0;",
|
||||||
|
"",
|
||||||
|
"for (var b in [ 1, 2, 3 ]) {",
|
||||||
|
" a = +a + 1 - .2;",
|
||||||
|
" console.log(a);",
|
||||||
|
"}",
|
||||||
|
].join("\n");
|
||||||
|
var result = reduce_test(code, {
|
||||||
|
compress: {
|
||||||
|
unsafe_math: true,
|
||||||
|
},
|
||||||
|
mangle: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// (beautified)",
|
||||||
|
code,
|
||||||
|
"// output: 0.8",
|
||||||
|
"// 1.6",
|
||||||
|
"// 2.4",
|
||||||
|
"// ",
|
||||||
|
"// minify: 0.8",
|
||||||
|
"// 1.6",
|
||||||
|
"// 2.4000000000000004",
|
||||||
|
"// ",
|
||||||
|
"// options: {",
|
||||||
|
'// "compress": {',
|
||||||
|
'// "unsafe_math": true',
|
||||||
|
"// },",
|
||||||
|
'// "mangle": false',
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should reduce infinite loops with reasonable performance", function() {
|
||||||
|
if (semver.satisfies(process.version, "0.10")) return;
|
||||||
|
this.timeout(120000);
|
||||||
|
var result = reduce_test("while (/9/.test(1 - .8));", {
|
||||||
|
compress: {
|
||||||
|
unsafe_math: true,
|
||||||
|
},
|
||||||
|
mangle: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code.replace(/ timed out after [0-9]+ms/, " timed out."), [
|
||||||
|
"// (beautified)",
|
||||||
|
"while (/9/.test(1 - .8)) {}",
|
||||||
|
"// output: Error: Script execution timed out.",
|
||||||
|
"// minify: ",
|
||||||
|
"// options: {",
|
||||||
|
'// "compress": {',
|
||||||
|
'// "unsafe_math": true',
|
||||||
|
"// },",
|
||||||
|
'// "mangle": false',
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
it("Should ignore difference in Error.message", function() {
|
||||||
|
var result = reduce_test("null[function() {\n}];");
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, (semver.satisfies(process.version, "0.10") ? [
|
||||||
|
"// Can't reproduce test failure",
|
||||||
|
"// minify options: {}",
|
||||||
|
] : [
|
||||||
|
"// No differences except in error message",
|
||||||
|
"// minify options: {}",
|
||||||
|
]).join("\n"));
|
||||||
|
});
|
||||||
|
it("Should report trailing whitespace difference in stringified format", function() {
|
||||||
|
var code = [
|
||||||
|
"for (var a in (1 - .8).toString()) {",
|
||||||
|
" console.log();",
|
||||||
|
"}",
|
||||||
|
].join("\n");
|
||||||
|
var result = reduce_test(code, {
|
||||||
|
compress: {
|
||||||
|
unsafe_math: true,
|
||||||
|
},
|
||||||
|
mangle: false,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"// (beautified)",
|
||||||
|
code,
|
||||||
|
"// (stringified)",
|
||||||
|
'// output: "\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n"',
|
||||||
|
'// minify: "\\n\\n\\n"',
|
||||||
|
"// options: {",
|
||||||
|
'// "compress": {',
|
||||||
|
'// "unsafe_math": true',
|
||||||
|
'// },',
|
||||||
|
'// "mangle": false',
|
||||||
|
"// }",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var readFileSync = require("fs").readFileSync;
|
var fs = require("fs");
|
||||||
var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
|
||||||
var UglifyJS = require("../node");
|
var UglifyJS = require("../node");
|
||||||
|
|
||||||
function read(path) {
|
function read(path) {
|
||||||
return readFileSync(path, "utf8");
|
return fs.readFileSync(path, "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
function source_map(code) {
|
function source_map(code) {
|
||||||
@@ -44,7 +43,7 @@ function prepare_map(sourceMap) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
return new SourceMapConsumer(result.map);
|
return JSON.parse(result.map);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("sourcemaps", function() {
|
describe("sourcemaps", function() {
|
||||||
@@ -87,14 +86,30 @@ describe("sourcemaps", function() {
|
|||||||
});
|
});
|
||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
assert.strictEqual(result.code, code);
|
assert.strictEqual(result.code, code);
|
||||||
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI","sourceRoot":"//foo.bar/"}');
|
assert.strictEqual(result.map, '{"version":3,"sourceRoot":"//foo.bar/","sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI"}');
|
||||||
|
});
|
||||||
|
it("Should produce same source map with DOS or UNIX line endings", function() {
|
||||||
|
var code = [
|
||||||
|
'console.log("\\',
|
||||||
|
'hello",',
|
||||||
|
'"world");',
|
||||||
|
];
|
||||||
|
var dos = UglifyJS.minify(code.join("\r\n"), {
|
||||||
|
sourceMap: true,
|
||||||
|
});
|
||||||
|
if (dos.error) throw dos.error;
|
||||||
|
var unix = UglifyJS.minify(code.join("\n"), {
|
||||||
|
sourceMap: true,
|
||||||
|
});
|
||||||
|
if (unix.error) throw unix.error;
|
||||||
|
assert.strictEqual(dos.map, unix.map);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("inSourceMap", function() {
|
describe("inSourceMap", function() {
|
||||||
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled", function() {
|
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-1236/simple.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-1236/simple.js"), {
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
content: read("./test/input/issue-1236/simple.js.map"),
|
content: read("test/input/issue-1236/simple.js.map"),
|
||||||
filename: "simple.min.js",
|
filename: "simple.min.js",
|
||||||
includeSources: true
|
includeSources: true
|
||||||
}
|
}
|
||||||
@@ -106,7 +121,7 @@ describe("sourcemaps", function() {
|
|||||||
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
||||||
});
|
});
|
||||||
it("Should process inline source map", function() {
|
it("Should process inline source map", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
|
||||||
compress: { toplevel: true },
|
compress: { toplevel: true },
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
content: "inline",
|
content: "inline",
|
||||||
@@ -115,10 +130,10 @@ describe("sourcemaps", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8"));
|
assert.strictEqual(result.code + "\n", read("test/input/issue-520/output.js"));
|
||||||
});
|
});
|
||||||
it("Should warn for missing inline source map", function() {
|
it("Should warn for missing inline source map", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-1323/sample.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-1323/sample.js"), {
|
||||||
mangle: false,
|
mangle: false,
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
content: "inline"
|
content: "inline"
|
||||||
@@ -130,8 +145,8 @@ describe("sourcemaps", function() {
|
|||||||
});
|
});
|
||||||
it("Should handle multiple input and inline source map", function() {
|
it("Should handle multiple input and inline source map", function() {
|
||||||
var result = UglifyJS.minify([
|
var result = UglifyJS.minify([
|
||||||
read("./test/input/issue-520/input.js"),
|
read("test/input/issue-520/input.js"),
|
||||||
read("./test/input/issue-1323/sample.js"),
|
read("test/input/issue-1323/sample.js"),
|
||||||
], {
|
], {
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
content: "inline",
|
content: "inline",
|
||||||
@@ -147,7 +162,7 @@ describe("sourcemaps", function() {
|
|||||||
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
|
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
|
||||||
});
|
});
|
||||||
it("Should drop source contents for includeSources=false", function() {
|
it("Should drop source contents for includeSources=false", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
|
||||||
compress: false,
|
compress: false,
|
||||||
mangle: false,
|
mangle: false,
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
@@ -170,7 +185,7 @@ describe("sourcemaps", function() {
|
|||||||
assert.ok(!("sourcesContent" in map));
|
assert.ok(!("sourcesContent" in map));
|
||||||
});
|
});
|
||||||
it("Should parse the correct sourceMappingURL", function() {
|
it("Should parse the correct sourceMappingURL", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-3294/input.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-3294/input.js"), {
|
||||||
compress: { toplevel: true },
|
compress: { toplevel: true },
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
content: "inline",
|
content: "inline",
|
||||||
@@ -179,10 +194,10 @@ describe("sourcemaps", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-3294/output.js", "utf8"));
|
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
|
||||||
});
|
});
|
||||||
it("Should work in presence of unrecognised annotations", function() {
|
it("Should work in presence of unrecognised annotations", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-3441/input.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
|
||||||
compress: false,
|
compress: false,
|
||||||
mangle: false,
|
mangle: false,
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
@@ -214,7 +229,7 @@ describe("sourcemaps", function() {
|
|||||||
assert.strictEqual(code, "var a=function(n){return n};");
|
assert.strictEqual(code, "var a=function(n){return n};");
|
||||||
});
|
});
|
||||||
it("Should work with max_line_len", function() {
|
it("Should work with max_line_len", function() {
|
||||||
var result = UglifyJS.minify(read("./test/input/issue-505/input.js"), {
|
var result = UglifyJS.minify(read("test/input/issue-505/input.js"), {
|
||||||
compress: {
|
compress: {
|
||||||
directives: false,
|
directives: false,
|
||||||
},
|
},
|
||||||
@@ -226,7 +241,7 @@ describe("sourcemaps", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
|
assert.strictEqual(result.code, read("test/input/issue-505/output.js"));
|
||||||
});
|
});
|
||||||
it("Should work with unicode characters", function() {
|
it("Should work with unicode characters", function() {
|
||||||
var code = [
|
var code = [
|
||||||
@@ -265,29 +280,33 @@ describe("sourcemaps", function() {
|
|||||||
it("Should copy over original sourcesContent", function() {
|
it("Should copy over original sourcesContent", function() {
|
||||||
var orig = get_map();
|
var orig = get_map();
|
||||||
var map = prepare_map(orig);
|
var map = prepare_map(orig);
|
||||||
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]);
|
assert.strictEqual(map.sources.length, 1);
|
||||||
|
assert.strictEqual(map.sources[0], "index.js");
|
||||||
|
assert.strictEqual(map.sourcesContent.length, 1);
|
||||||
|
assert.equal(map.sourcesContent[0], orig.sourcesContent[0]);
|
||||||
});
|
});
|
||||||
it("Should copy sourcesContent if sources are relative", function() {
|
it("Should copy sourcesContent if sources are relative", function() {
|
||||||
var relativeMap = get_map();
|
var relativeMap = get_map();
|
||||||
relativeMap.sources = ['./index.js'];
|
relativeMap.sources = ['./index.js'];
|
||||||
var map = prepare_map(relativeMap);
|
var map = prepare_map(relativeMap);
|
||||||
assert.notEqual(map.sourcesContent, null);
|
assert.strictEqual(map.sources.length, 1);
|
||||||
assert.equal(map.sourcesContent.length, 1);
|
assert.strictEqual(map.sources[0], "./index.js");
|
||||||
assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]);
|
assert.strictEqual(map.sourcesContent.length, 1);
|
||||||
|
assert.equal(map.sourcesContent[0], relativeMap.sourcesContent[0]);
|
||||||
});
|
});
|
||||||
it("Should not have invalid mappings from inputSourceMap", function() {
|
it("Should not have invalid mappings from inputSourceMap", function() {
|
||||||
var map = prepare_map(get_map());
|
var map = prepare_map(get_map());
|
||||||
// The original source has only 2 lines, check that mappings don't have more lines
|
// The original source has only 2 lines, check that mappings don't have more lines
|
||||||
var msg = "Mapping should not have higher line number than the original file had";
|
var msg = "Mapping should not have higher line number than the original file had";
|
||||||
map.eachMapping(function(mapping) {
|
var lines = map.mappings.split(/;/);
|
||||||
assert.ok(mapping.originalLine <= 2, msg);
|
assert.ok(lines.length <= 2, msg);
|
||||||
});
|
var indices = [ 0, 0, 1, 0, 0];
|
||||||
map.allGeneratedPositionsFor({
|
lines.forEach(function(segments) {
|
||||||
source: "index.js",
|
indices[0] = 0;
|
||||||
line: 1,
|
segments.split(/,/).forEach(function(segment) {
|
||||||
column: 1
|
UglifyJS.vlq_decode(indices, segment);
|
||||||
}).forEach(function(pos) {
|
assert.ok(indices[2] <= 2, msg);
|
||||||
assert.ok(pos.line <= 2, msg);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,30 +44,37 @@ function test(original, estree, description) {
|
|||||||
try_beautify(transformed.code);
|
try_beautify(transformed.code);
|
||||||
}
|
}
|
||||||
console.log("!!!!!! Failed... round", round);
|
console.log("!!!!!! Failed... round", round);
|
||||||
process.exit(1);
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var num_iterations = ufuzz.num_iterations;
|
var num_iterations = ufuzz.num_iterations;
|
||||||
|
var minify_options = require("./ufuzz/options.json").map(JSON.stringify);
|
||||||
|
minify_options.unshift(null);
|
||||||
for (var round = 1; round <= num_iterations; round++) {
|
for (var round = 1; round <= num_iterations; round++) {
|
||||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||||
var code = ufuzz.createTopLevelCode();
|
var code = ufuzz.createTopLevelCode();
|
||||||
var uglified = UglifyJS.minify(code, {
|
minify_options.forEach(function(options) {
|
||||||
compress: false,
|
var input = options ? UglifyJS.minify(code, JSON.parse(options)).code : code;
|
||||||
mangle: false,
|
var uglified = UglifyJS.minify(input, {
|
||||||
output: {
|
compress: false,
|
||||||
ast: true
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
ast: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var ok = test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()");
|
||||||
|
try {
|
||||||
|
ok = test(uglified.code, acorn.parse(input), "acorn.parse()") && ok;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("//=============================================================");
|
||||||
|
console.log("// acorn parser failed... round", round);
|
||||||
|
console.log(e);
|
||||||
|
console.log("// original code");
|
||||||
|
console.log(input);
|
||||||
}
|
}
|
||||||
|
if (!ok) process.exit(1);
|
||||||
});
|
});
|
||||||
test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()");
|
|
||||||
try {
|
|
||||||
test(uglified.code, acorn.parse(code), "acorn.parse()");
|
|
||||||
} catch (e) {
|
|
||||||
console.log("//=============================================================");
|
|
||||||
console.log("// acorn parser failed... round", round);
|
|
||||||
console.log(e);
|
|
||||||
console.log("// original code");
|
|
||||||
console.log(code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
console.log();
|
console.log();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
|
|
||||||
new Function("MOZ_SourceMap", "exports", require("../tools/node").FILES.map(function(file) {
|
new Function("exports", require("../tools/node").FILES.map(function(file) {
|
||||||
if (/exports\.js$/.test(file)) file = require.resolve("./exports");
|
if (/exports\.js$/.test(file)) file = require.resolve("./exports");
|
||||||
return fs.readFileSync(file, "utf8");
|
return fs.readFileSync(file, "utf8");
|
||||||
}).join("\n\n"))(require("source-map"), exports);
|
}).join("\n\n"))(exports);
|
||||||
|
|||||||
622
test/reduce.js
Normal file
622
test/reduce.js
Normal file
@@ -0,0 +1,622 @@
|
|||||||
|
var crypto = require("crypto");
|
||||||
|
var U = require("./node");
|
||||||
|
var List = U.List;
|
||||||
|
var os = require("os");
|
||||||
|
var sandbox = require("./sandbox");
|
||||||
|
|
||||||
|
// Reduce a ufuzz-style `console.log` based test case by iteratively replacing
|
||||||
|
// AST nodes with various permutations. Each AST_Statement in the tree is also
|
||||||
|
// speculatively dropped to determine whether it is needed. If the altered
|
||||||
|
// tree and the last known good tree produce the same non-nil error-free output
|
||||||
|
// after being run, then the permutation survives to the next generation and
|
||||||
|
// is the basis for subsequent iterations. The test case is reduced as a
|
||||||
|
// consequence of complex expressions being replaced with simpler ones.
|
||||||
|
// This function assumes that the testcase will not result in a parse or
|
||||||
|
// runtime Error. Note that a reduced test case will have different runtime
|
||||||
|
// output - it is not functionally equivalent to the original. The only criteria
|
||||||
|
// is that once the generated reduced test case is run without minification, it
|
||||||
|
// will produce different output from the code minified with `minify_options`.
|
||||||
|
// Returns a `minify` result object with an additonal boolean property `reduced`.
|
||||||
|
|
||||||
|
module.exports = function reduce_test(testcase, minify_options, reduce_options) {
|
||||||
|
if (testcase instanceof U.AST_Node) testcase = testcase.print_to_string();
|
||||||
|
minify_options = minify_options || {};
|
||||||
|
reduce_options = reduce_options || {};
|
||||||
|
var max_iterations = reduce_options.max_iterations || 1000;
|
||||||
|
var max_timeout = reduce_options.max_timeout || 10000;
|
||||||
|
var verbose = reduce_options.verbose;
|
||||||
|
var minify_options_json = JSON.stringify(minify_options, null, 2);
|
||||||
|
var result_cache = Object.create(null);
|
||||||
|
// the initial timeout to assess the viability of the test case must be large
|
||||||
|
var differs = producesDifferentResultWhenMinified(result_cache, testcase, minify_options, max_timeout);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
console.error("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
|
||||||
|
}
|
||||||
|
if (!differs) {
|
||||||
|
// same stdout result produced when minified
|
||||||
|
return {
|
||||||
|
code: [
|
||||||
|
"// Can't reproduce test failure",
|
||||||
|
"// minify options: " + to_comment(minify_options_json)
|
||||||
|
].join("\n")
|
||||||
|
};
|
||||||
|
} else if (differs.timed_out) {
|
||||||
|
return {
|
||||||
|
code: [
|
||||||
|
"// Can't reproduce test failure within " + max_timeout + "ms",
|
||||||
|
"// minify options: " + to_comment(minify_options_json)
|
||||||
|
].join("\n")
|
||||||
|
};
|
||||||
|
} else if (differs.error) {
|
||||||
|
return differs;
|
||||||
|
} else if (is_error(differs.unminified_result)
|
||||||
|
&& is_error(differs.minified_result)
|
||||||
|
&& differs.unminified_result.name == differs.minified_result.name) {
|
||||||
|
return {
|
||||||
|
code: [
|
||||||
|
"// No differences except in error message",
|
||||||
|
"// minify options: " + to_comment(minify_options_json)
|
||||||
|
].join("\n")
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
max_timeout = Math.min(100 * differs.elapsed, max_timeout);
|
||||||
|
// Replace expressions with constants that will be parsed into
|
||||||
|
// AST_Nodes as required. Each AST_Node has its own permutation count,
|
||||||
|
// so these replacements can't be shared.
|
||||||
|
// Although simpler replacements are generally faster and better,
|
||||||
|
// feel free to experiment with a different replacement set.
|
||||||
|
var REPLACEMENTS = [
|
||||||
|
// "null", "''", "false", "'foo'", "undefined", "9",
|
||||||
|
"1", "0",
|
||||||
|
];
|
||||||
|
|
||||||
|
// There's a relationship between each node's _permute counter and
|
||||||
|
// REPLACEMENTS.length which is why fractional _permutes were needed.
|
||||||
|
// One could scale all _permute operations by a factor of `steps`
|
||||||
|
// to only deal with integer operations, but this works well enough.
|
||||||
|
var steps = 4; // must be a power of 2
|
||||||
|
var step = 1 / steps; // 0.25 is exactly representable in floating point
|
||||||
|
|
||||||
|
var tt = new U.TreeTransformer(function(node, descend, in_list) {
|
||||||
|
if (CHANGED) return;
|
||||||
|
|
||||||
|
// quick ignores
|
||||||
|
if (node instanceof U.AST_Accessor) return;
|
||||||
|
if (node instanceof U.AST_Directive) return;
|
||||||
|
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
||||||
|
if (node instanceof U.AST_Label) return;
|
||||||
|
if (node instanceof U.AST_LabelRef) return;
|
||||||
|
if (!in_list && node instanceof U.AST_SymbolDeclaration) return;
|
||||||
|
if (node instanceof U.AST_Toplevel) return;
|
||||||
|
var parent = tt.parent();
|
||||||
|
if (node instanceof U.AST_SymbolFunarg && parent instanceof U.AST_Accessor) return;
|
||||||
|
|
||||||
|
// ensure that the _permute prop is a number.
|
||||||
|
// can not use `node.start._permute |= 0;` as it will erase fractional part.
|
||||||
|
if (typeof node.start._permute === "undefined") node.start._permute = 0;
|
||||||
|
|
||||||
|
// if node reached permutation limit - skip over it.
|
||||||
|
// no structural AST changes before this point.
|
||||||
|
if (node.start._permute >= REPLACEMENTS.length) return;
|
||||||
|
|
||||||
|
if (parent instanceof U.AST_Assign
|
||||||
|
&& parent.left === node
|
||||||
|
|| parent instanceof U.AST_Unary
|
||||||
|
&& parent.expression === node
|
||||||
|
&& ["++", "--", "delete"].indexOf(parent.operator) >= 0) {
|
||||||
|
// ignore lvalues
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((parent instanceof U.AST_For || parent instanceof U.AST_ForIn)
|
||||||
|
&& parent.init === node && node instanceof U.AST_Var) {
|
||||||
|
// preserve for (var ...)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// node specific permutations with no parent logic
|
||||||
|
|
||||||
|
if (node instanceof U.AST_Array) {
|
||||||
|
var expr = node.elements[0];
|
||||||
|
if (expr && !(expr instanceof U.AST_Hole)) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Binary) {
|
||||||
|
CHANGED = true;
|
||||||
|
var permute = ((node.start._permute += step) * steps | 0) % 4;
|
||||||
|
var expr = [
|
||||||
|
node.left,
|
||||||
|
node.right,
|
||||||
|
][ permute & 1 ];
|
||||||
|
if (permute < 2) return expr;
|
||||||
|
// wrap with console.log()
|
||||||
|
return new U.AST_Call({
|
||||||
|
expression: new U.AST_Dot({
|
||||||
|
expression: new U.AST_SymbolRef({
|
||||||
|
name: "console",
|
||||||
|
start: {},
|
||||||
|
}),
|
||||||
|
property: "log",
|
||||||
|
start: {},
|
||||||
|
}),
|
||||||
|
args: [ expr ],
|
||||||
|
start: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Catch || node instanceof U.AST_Finally) {
|
||||||
|
// drop catch or finally block
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Conditional) {
|
||||||
|
CHANGED = true;
|
||||||
|
return [
|
||||||
|
node.condition,
|
||||||
|
node.consequent,
|
||||||
|
node.alternative,
|
||||||
|
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_BlockStatement) {
|
||||||
|
if (in_list) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return List.splice(node.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Call) {
|
||||||
|
var expr = [
|
||||||
|
node.expression,
|
||||||
|
node.args[0],
|
||||||
|
null, // intentional
|
||||||
|
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||||
|
if (expr) {
|
||||||
|
CHANGED = true;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
if (node.expression instanceof U.AST_Function) {
|
||||||
|
// hoist and return expressions from the IIFE function expression
|
||||||
|
var body = node.expression.body;
|
||||||
|
node.expression.body = [];
|
||||||
|
var seq = [];
|
||||||
|
body.forEach(function(node) {
|
||||||
|
var expr = expr instanceof U.AST_Exit ? node.value : node.body;
|
||||||
|
if (expr instanceof U.AST_Node && !is_statement(expr)) {
|
||||||
|
// collect expressions from each statements' body
|
||||||
|
seq.push(expr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CHANGED = true;
|
||||||
|
return to_sequence(seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Defun) {
|
||||||
|
switch (((node.start._permute += step) * steps | 0) % 2) {
|
||||||
|
case 0:
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
case 1:
|
||||||
|
if (!has_exit(node)) {
|
||||||
|
// hoist function declaration body
|
||||||
|
var body = node.body;
|
||||||
|
node.body = [];
|
||||||
|
body.push(node); // retain function with empty body to be dropped later
|
||||||
|
CHANGED = true;
|
||||||
|
return List.splice(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_DWLoop) {
|
||||||
|
var expr = [
|
||||||
|
node.condition,
|
||||||
|
node.body,
|
||||||
|
null, // intentional
|
||||||
|
][ (node.start._permute * steps | 0) % 3 ];
|
||||||
|
node.start._permute += step;
|
||||||
|
if (!expr) {
|
||||||
|
if (node.body[0] instanceof U.AST_Break) {
|
||||||
|
if (node instanceof U.AST_Do) {
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
|
expr = node.condition; // AST_While - fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
||||||
|
CHANGED = true;
|
||||||
|
return to_statement(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_PropAccess) {
|
||||||
|
var expr = [
|
||||||
|
node.expression,
|
||||||
|
node.property instanceof U.AST_Node && node.property,
|
||||||
|
][ node.start._permute++ % 2 ];
|
||||||
|
if (expr) {
|
||||||
|
CHANGED = true;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_For) {
|
||||||
|
var expr = [
|
||||||
|
node.init,
|
||||||
|
node.condition,
|
||||||
|
node.step,
|
||||||
|
node.body,
|
||||||
|
][ (node.start._permute * steps | 0) % 4 ];
|
||||||
|
node.start._permute += step;
|
||||||
|
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
||||||
|
CHANGED = true;
|
||||||
|
return to_statement(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_ForIn) {
|
||||||
|
var expr = [
|
||||||
|
node.init,
|
||||||
|
node.object,
|
||||||
|
node.body,
|
||||||
|
][ (node.start._permute * steps | 0) % 3 ];
|
||||||
|
node.start._permute += step;
|
||||||
|
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
||||||
|
CHANGED = true;
|
||||||
|
return to_statement(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_If) {
|
||||||
|
var expr = [
|
||||||
|
node.condition,
|
||||||
|
node.body,
|
||||||
|
node.alternative,
|
||||||
|
][ (node.start._permute * steps | 0) % 3 ];
|
||||||
|
node.start._permute += step;
|
||||||
|
if (expr) {
|
||||||
|
// replace if statement with its condition, then block or else block
|
||||||
|
CHANGED = true;
|
||||||
|
return to_statement(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Object) {
|
||||||
|
// first property's value
|
||||||
|
var expr = node.properties[0] instanceof U.AST_ObjectKeyVal && node.properties[0].value;
|
||||||
|
if (expr) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_SimpleStatement) {
|
||||||
|
if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) {
|
||||||
|
// hoist simple statement IIFE function expression body
|
||||||
|
node.start._permute++;
|
||||||
|
if (!has_exit(node.body.expression)) {
|
||||||
|
var body = node.body.expression.body;
|
||||||
|
node.body.expression.body = [];
|
||||||
|
CHANGED = true;
|
||||||
|
return List.splice(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Switch) {
|
||||||
|
var expr = [
|
||||||
|
node.expression, // switch expression
|
||||||
|
node.body[0] && node.body[0].expression, // first case expression or undefined
|
||||||
|
node.body[0] && node.body[0], // first case body or undefined
|
||||||
|
][ (node.start._permute * steps | 0) % 4 ];
|
||||||
|
node.start._permute += step;
|
||||||
|
if (expr && (!(expr instanceof U.AST_Statement) || !has_loopcontrol(expr, node, parent))) {
|
||||||
|
CHANGED = true;
|
||||||
|
return expr instanceof U.AST_SwitchBranch ? new U.AST_BlockStatement({
|
||||||
|
body: expr.body.slice(),
|
||||||
|
start: {},
|
||||||
|
}) : to_statement(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Try) {
|
||||||
|
var body = [
|
||||||
|
node.body,
|
||||||
|
node.bcatch && node.bcatch.body,
|
||||||
|
node.bfinally && node.bfinally.body,
|
||||||
|
null, // intentional
|
||||||
|
][ (node.start._permute * steps | 0) % 4 ];
|
||||||
|
node.start._permute += step;
|
||||||
|
if (body) {
|
||||||
|
// replace try statement with try block, catch block, or finally block
|
||||||
|
CHANGED = true;
|
||||||
|
return new U.AST_BlockStatement({
|
||||||
|
body: body,
|
||||||
|
start: {},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// replace try with a break or return if first in try statement
|
||||||
|
if (node.body[0] instanceof U.AST_Break
|
||||||
|
|| node.body[0] instanceof U.AST_Return) {
|
||||||
|
CHANGED = true;
|
||||||
|
return node.body[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Unary) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return node.expression;
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Var) {
|
||||||
|
if (node.definitions.length == 1 && node.definitions[0].value) {
|
||||||
|
// first declaration value
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return to_statement(node.definitions[0].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_LabeledStatement) {
|
||||||
|
if (node.body instanceof U.AST_Statement
|
||||||
|
&& !has_loopcontrol(node.body, node.body, node)) {
|
||||||
|
// replace labelled statement with its non-labelled body
|
||||||
|
node.start._permute = REPLACEMENTS.length;
|
||||||
|
CHANGED = true;
|
||||||
|
return node.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_list) {
|
||||||
|
// special case to drop object properties and switch branches
|
||||||
|
if (parent instanceof U.AST_Object
|
||||||
|
|| parent instanceof U.AST_Switch && parent.expression != node) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace or skip statement
|
||||||
|
if (node instanceof U.AST_Statement) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove this node unless its the sole element of a (transient) sequence
|
||||||
|
if (!(parent instanceof U.AST_Sequence) || parent.expressions.length > 1) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace this node
|
||||||
|
var newNode = is_statement(node) ? new U.AST_EmptyStatement({
|
||||||
|
start: {},
|
||||||
|
}) : U.parse(REPLACEMENTS[node.start._permute % REPLACEMENTS.length | 0], {
|
||||||
|
expression: true,
|
||||||
|
});
|
||||||
|
newNode.start._permute = ++node.start._permute;
|
||||||
|
CHANGED = true;
|
||||||
|
return newNode;
|
||||||
|
}, function(node, in_list) {
|
||||||
|
if (node instanceof U.AST_Sequence) {
|
||||||
|
// expand single-element sequence
|
||||||
|
if (node.expressions.length == 1) return node.expressions[0];
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Try) {
|
||||||
|
// expand orphaned try block
|
||||||
|
if (!node.bcatch && !node.bfinally) return new U.AST_BlockStatement({
|
||||||
|
body: node.body,
|
||||||
|
start: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (node instanceof U.AST_Var) {
|
||||||
|
// remove empty var statement
|
||||||
|
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
||||||
|
start: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var pass = 1; pass <= 3; ++pass) {
|
||||||
|
var testcase_ast = U.parse(testcase);
|
||||||
|
testcase_ast.walk(new U.TreeWalker(function(node) {
|
||||||
|
// unshare start props to retain visit data between iterations
|
||||||
|
node.start = JSON.parse(JSON.stringify(node.start));
|
||||||
|
node.start._permute = 0;
|
||||||
|
}));
|
||||||
|
for (var c = 0; c < max_iterations; ++c) {
|
||||||
|
if (verbose) {
|
||||||
|
if (pass == 1 && c % 25 == 0) {
|
||||||
|
console.error("// reduce test pass "
|
||||||
|
+ pass + ", iteration " + c + ": " + testcase.length + " bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var CHANGED = false;
|
||||||
|
var code_ast = testcase_ast.clone(true).transform(tt);
|
||||||
|
if (!CHANGED) break;
|
||||||
|
try {
|
||||||
|
var code = code_ast.print_to_string();
|
||||||
|
} catch (ex) {
|
||||||
|
// AST is not well formed.
|
||||||
|
// no harm done - just log the error, ignore latest change and continue iterating.
|
||||||
|
console.error("*** Error generating code from AST.");
|
||||||
|
console.error(ex);
|
||||||
|
console.error("*** Discarding permutation and continuing.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var diff = producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout);
|
||||||
|
if (diff) {
|
||||||
|
if (diff.timed_out) {
|
||||||
|
// can't trust the validity of `code_ast` and `code` when timed out.
|
||||||
|
// no harm done - just ignore latest change and continue iterating.
|
||||||
|
} else if (diff.error) {
|
||||||
|
// something went wrong during minify() - could be malformed AST or genuine bug.
|
||||||
|
// no harm done - just log code & error, ignore latest change and continue iterating.
|
||||||
|
console.error("*** Error during minification.");
|
||||||
|
console.error(code);
|
||||||
|
console.error(diff.error);
|
||||||
|
console.error("*** Discarding permutation and continuing.");
|
||||||
|
} else if (is_error(diff.unminified_result)
|
||||||
|
&& is_error(diff.minified_result)
|
||||||
|
&& diff.unminified_result.name == diff.minified_result.name) {
|
||||||
|
// ignore difference in error messages caused by minification
|
||||||
|
} else {
|
||||||
|
// latest permutation is valid, so use it as the basis of new changes
|
||||||
|
testcase_ast = code_ast;
|
||||||
|
testcase = code;
|
||||||
|
differs = diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 0) break;
|
||||||
|
if (verbose) {
|
||||||
|
console.error("// reduce test pass " + pass + ": " + testcase.length + " bytes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testcase = try_beautify(result_cache, testcase, minify_options, differs.unminified_result, max_timeout);
|
||||||
|
var lines = [ "" ];
|
||||||
|
var unminified_result = strip_color_codes(differs.unminified_result);
|
||||||
|
var minified_result = strip_color_codes(differs.minified_result);
|
||||||
|
if (trim_trailing_whitespace(unminified_result) == trim_trailing_whitespace(minified_result)) {
|
||||||
|
lines.push(
|
||||||
|
"// (stringified)",
|
||||||
|
"// output: " + JSON.stringify(unminified_result),
|
||||||
|
"// minify: " + JSON.stringify(minified_result)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
lines.push(
|
||||||
|
"// output: " + to_comment(unminified_result),
|
||||||
|
"// minify: " + to_comment(minified_result)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
lines.push("// options: " + to_comment(minify_options_json));
|
||||||
|
testcase.code += lines.join("\n");
|
||||||
|
return testcase;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function strip_color_codes(value) {
|
||||||
|
return ("" + value).replace(/\u001b\[\d+m/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function to_comment(value) {
|
||||||
|
return ("" + value).replace(/\n/g, "\n// ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim_trailing_whitespace(value) {
|
||||||
|
return ("" + value).replace(/\s+$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function try_beautify(result_cache, testcase, minify_options, expected, timeout) {
|
||||||
|
var result = U.minify(testcase, {
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
beautify: true,
|
||||||
|
braces: true,
|
||||||
|
comments: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (result.error) return {
|
||||||
|
code: testcase,
|
||||||
|
};
|
||||||
|
var toplevel = sandbox.has_toplevel(minify_options);
|
||||||
|
var actual = run_code(result_cache, result.code, toplevel, timeout);
|
||||||
|
if (!sandbox.same_stdout(expected, actual)) return {
|
||||||
|
code: testcase,
|
||||||
|
};
|
||||||
|
result.code = "// (beautified)\n" + result.code;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function has_exit(fn) {
|
||||||
|
var found = false;
|
||||||
|
var tw = new U.TreeWalker(function(node) {
|
||||||
|
if (found) return found;
|
||||||
|
if (node instanceof U.AST_Exit) {
|
||||||
|
return found = true;
|
||||||
|
}
|
||||||
|
if (node instanceof U.AST_Scope && node !== fn) {
|
||||||
|
return true; // don't descend into nested functions
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fn.walk(tw);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
function has_loopcontrol(body, loop, label) {
|
||||||
|
var found = false;
|
||||||
|
var tw = new U.TreeWalker(function(node) {
|
||||||
|
if (found) return true;
|
||||||
|
if (node instanceof U.AST_LoopControl && this.loopcontrol_target(node) === loop) {
|
||||||
|
return found = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (label instanceof U.AST_LabeledStatement) tw.push(label);
|
||||||
|
tw.push(loop);
|
||||||
|
body.walk(tw);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_error(result) {
|
||||||
|
return typeof result == "object" && typeof result.name == "string" && typeof result.message == "string";
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_timed_out(result) {
|
||||||
|
return is_error(result) && /timed out/.test(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_statement(node) {
|
||||||
|
return node instanceof U.AST_Statement && !(node instanceof U.AST_Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge_sequence(array, node) {
|
||||||
|
if (node instanceof U.AST_Sequence) {
|
||||||
|
array.push.apply(array, node.expressions);
|
||||||
|
} else {
|
||||||
|
array.push(node);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function to_sequence(expressions) {
|
||||||
|
if (expressions.length == 0) return new U.AST_Number({value: 0, start: {}});
|
||||||
|
if (expressions.length == 1) return expressions[0];
|
||||||
|
return new U.AST_Sequence({
|
||||||
|
expressions: expressions.reduce(merge_sequence, []),
|
||||||
|
start: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function to_statement(node) {
|
||||||
|
return is_statement(node) ? node : new U.AST_SimpleStatement({
|
||||||
|
body: node,
|
||||||
|
start: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_code(result_cache, code, toplevel, timeout) {
|
||||||
|
var key = crypto.createHash("sha1").update(code).digest("base64");
|
||||||
|
return result_cache[key] || (result_cache[key] = sandbox.run_code(code, toplevel, timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
function producesDifferentResultWhenMinified(result_cache, code, minify_options, max_timeout) {
|
||||||
|
var minified = U.minify(code, minify_options);
|
||||||
|
if (minified.error) return minified;
|
||||||
|
|
||||||
|
var toplevel = sandbox.has_toplevel(minify_options);
|
||||||
|
var elapsed = Date.now();
|
||||||
|
var unminified_result = run_code(result_cache, code, toplevel, max_timeout);
|
||||||
|
elapsed = Date.now() - elapsed;
|
||||||
|
var timeout = Math.min(100 * elapsed, max_timeout);
|
||||||
|
var minified_result = run_code(result_cache, minified.code, toplevel, timeout);
|
||||||
|
|
||||||
|
if (sandbox.same_stdout(unminified_result, minified_result)) {
|
||||||
|
return is_timed_out(unminified_result) && is_timed_out(minified_result) && {
|
||||||
|
timed_out: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
unminified_result: unminified_result,
|
||||||
|
minified_result: minified_result,
|
||||||
|
elapsed: elapsed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Error.stackTraceLimit = Infinity;
|
||||||
@@ -54,14 +54,15 @@ function createContext() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.run_code = function(code, toplevel) {
|
exports.run_code = function(code, toplevel, timeout) {
|
||||||
|
timeout = timeout || 5000;
|
||||||
var stdout = "";
|
var stdout = "";
|
||||||
var original_write = process.stdout.write;
|
var original_write = process.stdout.write;
|
||||||
process.stdout.write = function(chunk) {
|
process.stdout.write = function(chunk) {
|
||||||
stdout += chunk;
|
stdout += chunk;
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
vm.runInContext(toplevel ? "(function(){" + code + "})()" : code, createContext(), { timeout: 5000 });
|
vm.runInContext(toplevel ? "(function(){" + code + "})()" : code, createContext(), { timeout: timeout });
|
||||||
return stdout;
|
return stdout;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
return ex;
|
return ex;
|
||||||
@@ -76,8 +77,9 @@ function strip_func_ids(text) {
|
|||||||
|
|
||||||
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
|
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
|
||||||
if (typeof expected != typeof actual) return false;
|
if (typeof expected != typeof actual) return false;
|
||||||
if (typeof expected != "string") {
|
if (typeof expected == "object" && typeof expected.name == "string" && typeof expected.message == "string") {
|
||||||
if (expected.name != actual.name) return false;
|
if (expected.name !== actual.name) return false;
|
||||||
|
if (typeof actual.message != "string") return false;
|
||||||
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
|
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
|
||||||
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
|
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
|
||||||
}
|
}
|
||||||
@@ -85,3 +87,8 @@ exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expec
|
|||||||
} : function(expected, actual) {
|
} : function(expected, actual) {
|
||||||
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
|
return typeof expected == typeof actual && strip_func_ids(expected) == strip_func_ids(actual);
|
||||||
};
|
};
|
||||||
|
exports.has_toplevel = function(options) {
|
||||||
|
return options.toplevel
|
||||||
|
|| options.mangle && options.mangle.toplevel
|
||||||
|
|| options.compress && options.compress.toplevel;
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ require("../../tools/exit");
|
|||||||
var UglifyJS = require("../..");
|
var UglifyJS = require("../..");
|
||||||
var randomBytes = require("crypto").randomBytes;
|
var randomBytes = require("crypto").randomBytes;
|
||||||
var sandbox = require("../sandbox");
|
var sandbox = require("../sandbox");
|
||||||
|
var reduce_test = require("../reduce");
|
||||||
|
|
||||||
var MAX_GENERATED_TOPLEVELS_PER_RUN = 1;
|
var MAX_GENERATED_TOPLEVELS_PER_RUN = 1;
|
||||||
var MAX_GENERATION_RECURSION_DEPTH = 12;
|
var MAX_GENERATION_RECURSION_DEPTH = 12;
|
||||||
@@ -741,6 +742,8 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || a || 3).toString() ";
|
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || a || 3).toString() ";
|
||||||
case p++:
|
case p++:
|
||||||
return " /[abc4]/.test(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) ";
|
return " /[abc4]/.test(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) ";
|
||||||
|
case p++:
|
||||||
|
return " /[abc4]/g.exec(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) ";
|
||||||
case p++:
|
case p++:
|
||||||
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) +
|
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) +
|
||||||
") || " + rng(10) + ").toString()[" +
|
") || " + rng(10) + ").toString()[" +
|
||||||
@@ -769,6 +772,12 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
|
if (rng(16) == 0) {
|
||||||
|
var name = getVarName();
|
||||||
|
var fn = name + "." + getDotKey();
|
||||||
|
called[name] = true;
|
||||||
|
return name + " && " + "typeof " + fn + ' == "function" && --_calls_ >= 0 && ' + fn + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||||
|
}
|
||||||
var name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
var name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
||||||
called[name] = true;
|
called[name] = true;
|
||||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||||
@@ -1009,7 +1018,7 @@ function log_suspects(minify_options, component) {
|
|||||||
var defs = default_options[component];
|
var defs = default_options[component];
|
||||||
var suspects = Object.keys(defs).filter(function(name) {
|
var suspects = Object.keys(defs).filter(function(name) {
|
||||||
var flip = name == "keep_fargs";
|
var flip = name == "keep_fargs";
|
||||||
if (flip ? name in options : (name in options ? options : defs)[name]) {
|
if (flip === !(name in options ? options : defs)[name]) {
|
||||||
var m = JSON.parse(JSON.stringify(minify_options));
|
var m = JSON.parse(JSON.stringify(minify_options));
|
||||||
var o = JSON.parse(JSON.stringify(options));
|
var o = JSON.parse(JSON.stringify(options));
|
||||||
o[name] = flip;
|
o[name] = flip;
|
||||||
@@ -1019,7 +1028,7 @@ function log_suspects(minify_options, component) {
|
|||||||
errorln("Error testing options." + component + "." + name);
|
errorln("Error testing options." + component + "." + name);
|
||||||
errorln(result.error);
|
errorln(result.error);
|
||||||
} else {
|
} else {
|
||||||
var r = sandbox.run_code(result.code, m.toplevel);
|
var r = sandbox.run_code(result.code, sandbox.has_toplevel(m));
|
||||||
return sandbox.same_stdout(original_result, r);
|
return sandbox.same_stdout(original_result, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1033,42 +1042,63 @@ function log_suspects(minify_options, component) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function log_rename(options) {
|
function log_suspects_global(options) {
|
||||||
var m = JSON.parse(JSON.stringify(options));
|
var o = {};
|
||||||
m.rename = false;
|
UglifyJS.minify("", o);
|
||||||
var result = UglifyJS.minify(original_code, m);
|
var suspects = Object.keys(o).filter(function(component) {
|
||||||
if (result.error) {
|
return typeof o[component] != "object";
|
||||||
errorln("Error testing options.rename");
|
}).filter(function(component) {
|
||||||
errorln(result.error);
|
var m = JSON.parse(options);
|
||||||
} else {
|
m[component] = false;
|
||||||
var r = sandbox.run_code(result.code, m.toplevel);
|
var result = UglifyJS.minify(original_code, m);
|
||||||
if (sandbox.same_stdout(original_result, r)) {
|
if (result.error) {
|
||||||
errorln("Suspicious options:");
|
errorln("Error testing options." + component);
|
||||||
errorln(" rename");
|
errorln(result.error);
|
||||||
errorln();
|
} else {
|
||||||
|
var r = sandbox.run_code(result.code, sandbox.has_toplevel(m));
|
||||||
|
return sandbox.same_stdout(original_result, r);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
if (suspects.length > 0) {
|
||||||
|
errorln("Suspicious options:");
|
||||||
|
suspects.forEach(function(name) {
|
||||||
|
errorln(" " + name);
|
||||||
|
});
|
||||||
|
errorln();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function log(options) {
|
function log(options) {
|
||||||
options = JSON.parse(options);
|
var toplevel = sandbox.has_toplevel(JSON.parse(options));
|
||||||
if (!ok) errorln("\n\n\n\n\n\n!!!!!!!!!!\n\n\n");
|
if (!ok) errorln("\n\n\n\n\n\n!!!!!!!!!!\n\n\n");
|
||||||
errorln("//=============================================================");
|
errorln("//=============================================================");
|
||||||
if (!ok) errorln("// !!!!!! Failed... round " + round);
|
if (!ok) errorln("// !!!!!! Failed... round " + round);
|
||||||
errorln("// original code");
|
errorln("// original code");
|
||||||
try_beautify(original_code, options.toplevel, original_result, errorln);
|
try_beautify(original_code, toplevel, original_result, errorln);
|
||||||
errorln();
|
errorln();
|
||||||
errorln();
|
errorln();
|
||||||
errorln("//-------------------------------------------------------------");
|
errorln("//-------------------------------------------------------------");
|
||||||
if (typeof uglify_code == "string") {
|
if (typeof uglify_code == "string") {
|
||||||
errorln("// uglified code");
|
errorln("// uglified code");
|
||||||
try_beautify(uglify_code, options.toplevel, uglify_result, errorln);
|
try_beautify(uglify_code, toplevel, uglify_result, errorln);
|
||||||
errorln();
|
errorln();
|
||||||
errorln();
|
errorln();
|
||||||
errorln("original result:");
|
errorln("original result:");
|
||||||
errorln(original_result);
|
errorln(original_result);
|
||||||
errorln("uglified result:");
|
errorln("uglified result:");
|
||||||
errorln(uglify_result);
|
errorln(uglify_result);
|
||||||
|
errorln("//-------------------------------------------------------------");
|
||||||
|
var reduced = reduce_test(original_code, JSON.parse(options), {
|
||||||
|
verbose: false,
|
||||||
|
}).code;
|
||||||
|
if (reduced) {
|
||||||
|
errorln();
|
||||||
|
errorln("// reduced test case (output will differ)");
|
||||||
|
errorln();
|
||||||
|
errorln(reduced);
|
||||||
|
errorln();
|
||||||
|
errorln("//-------------------------------------------------------------");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
errorln("// !!! uglify failed !!!");
|
errorln("// !!! uglify failed !!!");
|
||||||
errorln(uglify_code);
|
errorln(uglify_code);
|
||||||
@@ -1080,11 +1110,11 @@ function log(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
errorln("minify(options):");
|
errorln("minify(options):");
|
||||||
errorln(JSON.stringify(options, null, 2));
|
errorln(JSON.stringify(JSON.parse(options), null, 2));
|
||||||
errorln();
|
errorln();
|
||||||
if (!ok && typeof uglify_code == "string") {
|
if (!ok && typeof uglify_code == "string") {
|
||||||
Object.keys(default_options).forEach(log_suspects.bind(null, options));
|
Object.keys(default_options).forEach(log_suspects.bind(null, JSON.parse(options)));
|
||||||
log_rename(options);
|
log_suspects_global(options);
|
||||||
errorln("!!!!!! Failed... round " + round);
|
errorln("!!!!!! Failed... round " + round);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1119,16 +1149,17 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
if (!errored) orig_result.push(sandbox.run_code(original_code, true));
|
if (!errored) orig_result.push(sandbox.run_code(original_code, true));
|
||||||
(errored ? fallback_options : minify_options).forEach(function(options) {
|
(errored ? fallback_options : minify_options).forEach(function(options) {
|
||||||
var o = JSON.parse(options);
|
var o = JSON.parse(options);
|
||||||
|
var toplevel = sandbox.has_toplevel(o);
|
||||||
uglify_code = UglifyJS.minify(original_code, o);
|
uglify_code = UglifyJS.minify(original_code, o);
|
||||||
original_result = orig_result[o.toplevel ? 1 : 0];
|
original_result = orig_result[toplevel ? 1 : 0];
|
||||||
if (!uglify_code.error) {
|
if (!uglify_code.error) {
|
||||||
uglify_code = uglify_code.code;
|
uglify_code = uglify_code.code;
|
||||||
uglify_result = sandbox.run_code(uglify_code, o.toplevel);
|
uglify_result = sandbox.run_code(uglify_code, toplevel);
|
||||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||||
if (!ok && typeof uglify_result == "string" && o.compress.unsafe_math) {
|
if (!ok && typeof uglify_result == "string" && o.compress.unsafe_math) {
|
||||||
ok = fuzzy_match(original_result, uglify_result);
|
ok = fuzzy_match(original_result, uglify_result);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"));
|
var fuzzy_result = sandbox.run_code(original_code.replace(/( - 0\.1){3}/g, " - 0.3"), toplevel);
|
||||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1142,7 +1173,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
else if (errored) {
|
else if (errored) {
|
||||||
println("//=============================================================");
|
println("//=============================================================");
|
||||||
println("// original code");
|
println("// original code");
|
||||||
try_beautify(original_code, o.toplevel, original_result, println);
|
try_beautify(original_code, toplevel, original_result, println);
|
||||||
println();
|
println();
|
||||||
println();
|
println();
|
||||||
println("original result:");
|
println("original result:");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
exports["Dictionary"] = Dictionary;
|
exports["Dictionary"] = Dictionary;
|
||||||
|
exports["List"] = List;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["parse"] = parse;
|
exports["parse"] = parse;
|
||||||
exports["push_uniq"] = push_uniq;
|
exports["push_uniq"] = push_uniq;
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ exports.FILES = [
|
|||||||
require.resolve("./exports.js"),
|
require.resolve("./exports.js"),
|
||||||
];
|
];
|
||||||
|
|
||||||
new Function("MOZ_SourceMap", "exports", function() {
|
new Function("exports", function() {
|
||||||
var code = exports.FILES.map(function(file) {
|
var code = exports.FILES.map(function(file) {
|
||||||
return fs.readFileSync(file, "utf8");
|
return fs.readFileSync(file, "utf8");
|
||||||
});
|
});
|
||||||
code.push("exports.describe_ast = " + describe_ast.toString());
|
code.push("exports.describe_ast = " + describe_ast.toString());
|
||||||
return code.join("\n\n");
|
return code.join("\n\n");
|
||||||
}())(require("source-map"), exports);
|
}())(exports);
|
||||||
|
|
||||||
function describe_ast() {
|
function describe_ast() {
|
||||||
var out = OutputStream({ beautify: true });
|
var out = OutputStream({ beautify: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user