1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// Testing UglifyJS <-> SpiderMonkey AST conversion
"use strict";
var acorn = require("acorn");
var ufuzz = require("./ufuzz");
var UglifyJS = require("..");
function try_beautify(code) {
var beautified = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
braces: true,
}
});
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
console.log(code);
} else {
console.log("// (beautified)");
console.log(beautified.code);
}
}
function validate(ast) {
try {
ast.walk(new UglifyJS.TreeWalker(function(node) {
node.validate();
}));
} catch (e) {
return { error: e };
}
return UglifyJS.minify(ast, {
compress: false,
mangle: false,
validate: true,
});
}
function fuzzy(code) {
return code.replace(/\bimport\s*\{\s*\}\s*from\s*(['"])/g, "import$1")
.replace(/\b(import\b.*?)\s*,\s*\{\s*\}\s*(from\s*['"])/g, "$1 $2");
}
function test(original, estree, description) {
var transformed = validate(UglifyJS.AST_Node.from_mozilla_ast(estree));
if (transformed.error || original !== transformed.code && fuzzy(original) !== fuzzy(transformed.code)) {
console.log("//=============================================================");
console.log("// !!!!!! Failed... round", round);
console.log("// original code");
try_beautify(original);
console.log();
console.log();
console.log("//-------------------------------------------------------------");
console.log("//", description);
if (transformed.error) {
console.log(transformed.error.stack);
} else {
try_beautify(transformed.code);
}
console.log("!!!!!! Failed... round", round);
return false;
}
return true;
}
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++) {
process.stdout.write(round + " of " + num_iterations + "\r");
var code = ufuzz.createTopLevelCode();
minify_options.forEach(function(options) {
var input = options ? UglifyJS.minify(code, JSON.parse(options)).code : code;
var uglified = UglifyJS.minify(input, {
compress: false,
mangle: false,
output: {
ast: true,
},
});
var ok = true;
try {
var estree = uglified.ast.to_mozilla_ast();
} catch (e) {
ok = false;
console.log("//=============================================================");
console.log("// AST_Node.to_mozilla_ast() failed... round", round);
console.log(e);
console.log("// original code");
console.log(input);
}
if (ok) ok = test(uglified.code, estree, "AST_Node.to_mozilla_ast()");
if (ok) try {
ok = test(uglified.code, acorn.parse(input, {
ecmaVersion: "latest",
locations: true,
sourceType: "module",
}), "acorn.parse()");
} catch (e) {
if (ufuzz.verbose) {
console.log("//=============================================================");
console.log("// acorn parser failed... round", round);
console.log(e);
console.log("// original code");
console.log(input);
}
}
if (!ok) process.exit(1);
});
}
console.log();
|