Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bce7ee5f6a | ||
|
|
b39043f3ab | ||
|
|
caf96acb08 | ||
|
|
c76749084b | ||
|
|
5843494ee2 | ||
|
|
efa21ae3e6 | ||
|
|
24d9633a35 | ||
|
|
7963b96681 | ||
|
|
8c62d854ce | ||
|
|
69931574e1 | ||
|
|
b5af8a1914 | ||
|
|
c14d09ba84 | ||
|
|
4fc39d8dad | ||
|
|
0b7c70f726 | ||
|
|
f72d3029dd | ||
|
|
1a0d6edc81 | ||
|
|
7b59b2f5b2 | ||
|
|
7bc7704edf | ||
|
|
14e712ee80 | ||
|
|
f83adcc995 | ||
|
|
df8a99439a | ||
|
|
6b91d12ec3 | ||
|
|
f37b91879f | ||
|
|
d835c72c80 | ||
|
|
c4cebb4b01 | ||
|
|
d51a00a450 | ||
|
|
fc0f168a0c | ||
|
|
a0ca595c2c | ||
|
|
1a314e9f60 | ||
|
|
6fcbd5e217 | ||
|
|
22cea023d1 | ||
|
|
70d4477e05 | ||
|
|
838f837379 | ||
|
|
82a8b6f612 | ||
|
|
69fc7ca8da | ||
|
|
0a79496e0a | ||
|
|
9e87edfc2e | ||
|
|
27211cf2d5 | ||
|
|
b5ce199711 | ||
|
|
c71ed91e63 | ||
|
|
f7545d0f1c | ||
|
|
59eecb6bf5 | ||
|
|
d83c6490ab | ||
|
|
7362f57966 | ||
|
|
eaa2c1f6af | ||
|
|
6a916523d4 | ||
|
|
ba7069d52b | ||
|
|
4dd7d0e39b | ||
|
|
90199d0a96 | ||
|
|
b82fd0ad41 | ||
|
|
183da16896 | ||
|
|
87857b0f1b | ||
|
|
e5f6a88233 | ||
|
|
8d0b00317e | ||
|
|
db49daf365 | ||
|
|
923deeff35 | ||
|
|
0b62a28b47 | ||
|
|
44116c6d2b | ||
|
|
b5bab254ce | ||
|
|
81603ecd15 | ||
|
|
e67553fa55 | ||
|
|
fcf542f262 | ||
|
|
8adfc29f91 | ||
|
|
02f47e1713 | ||
|
|
07f64d4050 | ||
|
|
6982a0554c | ||
|
|
fa3250199a | ||
|
|
06b9894c19 | ||
|
|
9f9db504d7 | ||
|
|
82ae95c334 | ||
|
|
9a5e2052c4 | ||
|
|
b1410be443 | ||
|
|
12985d86c2 | ||
|
|
49bfc6b555 | ||
|
|
d1c6bb8c7c | ||
|
|
5c169615a8 |
10
.github/ISSUE_TEMPLATE.md
vendored
10
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,11 +1,7 @@
|
||||
**Bug report or feature request?**
|
||||
**Bug report or feature request?**
|
||||
|
||||
<!-- Note: sub-optimal but correct code is not a bug -->
|
||||
|
||||
**ES5 or ES6+ input?**
|
||||
|
||||
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
|
||||
|
||||
**Uglify version (`uglifyjs -V`)**
|
||||
|
||||
**JavaScript input**
|
||||
@@ -24,6 +20,6 @@
|
||||
**JavaScript output or error produced.**
|
||||
|
||||
<!--
|
||||
Note: `uglify-js` only supports ES5.
|
||||
Those wishing to minify ES6 should use `uglify-es`.
|
||||
Note: `uglify-js` only supports JavaScript.
|
||||
Those wishing to minify ES6+ should transpile first.
|
||||
-->
|
||||
|
||||
17
README.md
17
README.md
@@ -104,6 +104,8 @@ a double dash to prevent input files being used as option arguments:
|
||||
sequences.
|
||||
--config-file <file> Read `minify()` options from JSON file.
|
||||
-d, --define <expr>[=value] Global definitions.
|
||||
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
|
||||
argument(s) & value(s).
|
||||
--ie8 Support non-standard Internet Explorer 8.
|
||||
Equivalent to setting `ie8: true` in `minify()`
|
||||
for `compress`, `mangle` and `output` options.
|
||||
@@ -118,7 +120,8 @@ a double dash to prevent input files being used as option arguments:
|
||||
JS that was generated from some other original
|
||||
code. Specify "inline" if the source map is
|
||||
included within the sources.
|
||||
`filename` Name and/or location of the output source.
|
||||
`filename` Filename and/or location of the output source
|
||||
(sets `file` attribute in source map).
|
||||
`includeSources` Pass this flag if you want to include
|
||||
the content of source files in the
|
||||
source map as sourcesContent property.
|
||||
@@ -149,7 +152,9 @@ debugging your compressed JavaScript. To get a source map, pass
|
||||
|
||||
Additional options:
|
||||
|
||||
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
|
||||
- `--source-map "filename='<NAME>'"` to specify the name of the source map. The value of
|
||||
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
|
||||
in source map file.
|
||||
|
||||
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
|
||||
|
||||
@@ -685,7 +690,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
|
||||
function won't produce any side effect, in which case the whole
|
||||
statement would get discarded. The current implementation adds some
|
||||
overhead (compression will be slower).
|
||||
overhead (compression will be slower). Make sure symbols under `pure_funcs`
|
||||
are also under `mangle.reserved` to avoid mangling.
|
||||
|
||||
- `pure_getters` (default: `"strict"`) -- If you pass `true` for
|
||||
this, UglifyJS will assume that object property access
|
||||
@@ -1040,8 +1046,9 @@ var result = UglifyJS.minify(ast, {
|
||||
### Working with Uglify AST
|
||||
|
||||
Transversal and transformation of the native AST can be performed through
|
||||
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and
|
||||
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively.
|
||||
[`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
|
||||
[`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
|
||||
respectively.
|
||||
|
||||
### ESTree / SpiderMonkey AST
|
||||
|
||||
|
||||
24
bin/uglifyjs
24
bin/uglifyjs
@@ -40,14 +40,15 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
|
||||
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s).");
|
||||
program.option("--ie8", "Support non-standard Internet Explorer 8.");
|
||||
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
|
||||
program.option("--name-cache <file>", "File to hold mangled name mappings.");
|
||||
program.option("--rename", "Force symbol expansion.");
|
||||
program.option("--no-rename", "Disable symbol expansion.");
|
||||
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
|
||||
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
|
||||
program.option("--timings", "Display operations run time on STDERR.")
|
||||
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
|
||||
program.option("--timings", "Display operations run time on STDERR.");
|
||||
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
|
||||
program.option("--verbose", "Print diagnostic messages.");
|
||||
program.option("--warn", "Print warning messages.");
|
||||
@@ -61,6 +62,7 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
||||
}
|
||||
[
|
||||
"compress",
|
||||
"enclose",
|
||||
"ie8",
|
||||
"mangle",
|
||||
"sourceMap",
|
||||
@@ -176,6 +178,11 @@ function run() {
|
||||
UglifyJS.AST_Node.warn_function = function(msg) {
|
||||
print_error("WARN: " + msg);
|
||||
};
|
||||
var content = program.sourceMap && program.sourceMap.content;
|
||||
if (content && content != "inline") {
|
||||
print_error("INFO: Using input source map: " + content);
|
||||
options.sourceMap.content = read_file(content, content);
|
||||
}
|
||||
if (program.timings) options.timings = true;
|
||||
try {
|
||||
if (program.parse) {
|
||||
@@ -377,19 +384,6 @@ function parse_js(flag) {
|
||||
}
|
||||
}
|
||||
|
||||
function parse_source_map() {
|
||||
var parse = parse_js();
|
||||
return function(value, options) {
|
||||
var hasContent = options && "content" in options;
|
||||
var settings = parse(value, options);
|
||||
if (!hasContent && settings.content && settings.content != "inline") {
|
||||
print_error("INFO: Using input source map: " + settings.content);
|
||||
settings.content = read_file(settings.content, settings.content);
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
function skip_key(key) {
|
||||
return skip_keys.indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
29
lib/ast.js
29
lib/ast.js
@@ -314,6 +314,9 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
|
||||
if (this.functions) node.functions = this.functions.clone();
|
||||
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
||||
return node;
|
||||
},
|
||||
pinned: function() {
|
||||
return this.uses_eval || this.uses_with;
|
||||
}
|
||||
}, AST_Block);
|
||||
|
||||
@@ -332,6 +335,23 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
}
|
||||
}));
|
||||
return wrapped_tl;
|
||||
},
|
||||
wrap_enclose: function(args_values) {
|
||||
if (typeof args_values != "string") args_values = "";
|
||||
var index = args_values.indexOf(":");
|
||||
if (index < 0) index = args_values.length;
|
||||
var body = this.body;
|
||||
return parse([
|
||||
"(function(",
|
||||
args_values.slice(0, index),
|
||||
'){"$ORIG"})(',
|
||||
args_values.slice(index + 1),
|
||||
")"
|
||||
].join("")).transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
||||
return MAP.splice(body);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}, AST_Scope);
|
||||
|
||||
@@ -543,12 +563,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
|
||||
args: "[AST_Node*] array of arguments"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
var args = this.args;
|
||||
for (var i = 0, len = args.length; i < len; i++) {
|
||||
args[i]._walk(visitor);
|
||||
}
|
||||
return visitor._visit(this, function() {
|
||||
this.expression._walk(visitor);
|
||||
this.args.forEach(function(node) {
|
||||
node._walk(visitor);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
745
lib/compress.js
745
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -7,15 +7,23 @@ var to_base64 = typeof btoa == "undefined" ? function(str) {
|
||||
return new Buffer(str).toString("base64");
|
||||
} : btoa;
|
||||
|
||||
function read_source_map(code) {
|
||||
function read_source_map(name, code) {
|
||||
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
|
||||
if (!match) {
|
||||
AST_Node.warn("inline source map not found");
|
||||
AST_Node.warn("inline source map not found: " + name);
|
||||
return null;
|
||||
}
|
||||
return to_ascii(match[2]);
|
||||
}
|
||||
|
||||
function parse_source_map(content) {
|
||||
try {
|
||||
return JSON.parse(content);
|
||||
} catch (ex) {
|
||||
throw new Error("invalid input source map: " + content);
|
||||
}
|
||||
}
|
||||
|
||||
function set_shorthand(name, options, keys) {
|
||||
if (options[name]) {
|
||||
keys.forEach(function(key) {
|
||||
@@ -47,6 +55,7 @@ function minify(files, options) {
|
||||
try {
|
||||
options = defaults(options, {
|
||||
compress: {},
|
||||
enclose: false,
|
||||
ie8: false,
|
||||
keep_fnames: false,
|
||||
mangle: {},
|
||||
@@ -113,7 +122,7 @@ function minify(files, options) {
|
||||
};
|
||||
}
|
||||
if (timings) timings.parse = Date.now();
|
||||
var toplevel;
|
||||
var source_maps, toplevel;
|
||||
if (files instanceof AST_Toplevel) {
|
||||
toplevel = files;
|
||||
} else {
|
||||
@@ -122,13 +131,23 @@ function minify(files, options) {
|
||||
}
|
||||
options.parse = options.parse || {};
|
||||
options.parse.toplevel = null;
|
||||
var source_map_content = options.sourceMap && options.sourceMap.content;
|
||||
if (typeof source_map_content == "string" && source_map_content != "inline") {
|
||||
source_map_content = parse_source_map(source_map_content);
|
||||
}
|
||||
source_maps = source_map_content && Object.create(null);
|
||||
for (var name in files) if (HOP(files, name)) {
|
||||
options.parse.filename = name;
|
||||
options.parse.toplevel = parse(files[name], options.parse);
|
||||
if (options.sourceMap && options.sourceMap.content == "inline") {
|
||||
if (Object.keys(files).length > 1)
|
||||
throw new Error("inline source map only works with singular input");
|
||||
options.sourceMap.content = read_source_map(files[name]);
|
||||
if (source_maps) {
|
||||
if (source_map_content == "inline") {
|
||||
var inlined_content = read_source_map(name, files[name]);
|
||||
if (inlined_content) {
|
||||
source_maps[name] = parse_source_map(inlined_content);
|
||||
}
|
||||
} else {
|
||||
source_maps[name] = source_map_content;
|
||||
}
|
||||
}
|
||||
}
|
||||
toplevel = options.parse.toplevel;
|
||||
@@ -139,6 +158,9 @@ function minify(files, options) {
|
||||
if (options.wrap) {
|
||||
toplevel = toplevel.wrap_commonjs(options.wrap);
|
||||
}
|
||||
if (options.enclose) {
|
||||
toplevel = toplevel.wrap_enclose(options.enclose);
|
||||
}
|
||||
if (timings) timings.rename = Date.now();
|
||||
if (options.rename) {
|
||||
toplevel.figure_out_scope(options.mangle);
|
||||
@@ -164,12 +186,9 @@ function minify(files, options) {
|
||||
}
|
||||
if (!HOP(options.output, "code") || options.output.code) {
|
||||
if (options.sourceMap) {
|
||||
if (typeof options.sourceMap.content == "string") {
|
||||
options.sourceMap.content = JSON.parse(options.sourceMap.content);
|
||||
}
|
||||
options.output.source_map = SourceMap({
|
||||
file: options.sourceMap.filename,
|
||||
orig: options.sourceMap.content,
|
||||
orig: source_maps,
|
||||
root: options.sourceMap.root
|
||||
});
|
||||
if (options.sourceMap.includeSources) {
|
||||
@@ -178,6 +197,8 @@ function minify(files, options) {
|
||||
} else for (var name in files) if (HOP(files, name)) {
|
||||
options.output.source_map.get().setSourceContent(name, files[name]);
|
||||
}
|
||||
} else {
|
||||
options.output.source_map.get()._sourcesContents = null;
|
||||
}
|
||||
}
|
||||
delete options.output.ast;
|
||||
|
||||
@@ -180,6 +180,17 @@
|
||||
end : my_end_token(M)
|
||||
};
|
||||
if (val === null) return new AST_Null(args);
|
||||
var rx = M.regex;
|
||||
if (rx && rx.pattern) {
|
||||
// RegExpLiteral as per ESTree AST spec
|
||||
args.value = new RegExp(rx.pattern, rx.flags);
|
||||
args.value.raw_source = rx.pattern;
|
||||
return new AST_RegExp(args);
|
||||
} else if (rx) {
|
||||
// support legacy RegExp
|
||||
args.value = M.regex && M.raw ? M.raw : val;
|
||||
return new AST_RegExp(args);
|
||||
}
|
||||
switch (typeof val) {
|
||||
case "string":
|
||||
args.value = val;
|
||||
@@ -189,16 +200,6 @@
|
||||
return new AST_Number(args);
|
||||
case "boolean":
|
||||
return new (val ? AST_True : AST_False)(args);
|
||||
default:
|
||||
var rx = M.regex;
|
||||
if (rx && rx.pattern) {
|
||||
// RegExpLiteral as per ESTree AST spec
|
||||
args.value = new RegExp(rx.pattern, rx.flags).toString();
|
||||
} else {
|
||||
// support legacy RegExp
|
||||
args.value = M.regex && M.raw ? M.raw : val;
|
||||
}
|
||||
return new AST_RegExp(args);
|
||||
}
|
||||
},
|
||||
Identifier: function(M) {
|
||||
@@ -410,14 +411,15 @@
|
||||
});
|
||||
|
||||
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
|
||||
var value = M.value;
|
||||
var flags = M.value.toString().match(/[gimuy]*$/)[0];
|
||||
var value = "/" + M.value.raw_source + "/" + flags;
|
||||
return {
|
||||
type: "Literal",
|
||||
value: value,
|
||||
raw: value.toString(),
|
||||
raw: value,
|
||||
regex: {
|
||||
pattern: value.source,
|
||||
flags: value.toString().match(/[gimuy]*$/)[0]
|
||||
pattern: M.value.raw_source,
|
||||
flags: flags
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -564,6 +566,21 @@
|
||||
FROM_MOZ_STACK = [];
|
||||
var ast = from_moz(node);
|
||||
FROM_MOZ_STACK = save_stack;
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_LabelRef) {
|
||||
for (var level = 0, parent; parent = this.parent(level); level++) {
|
||||
if (parent instanceof AST_Scope) break;
|
||||
if (parent instanceof AST_LabeledStatement && parent.label.name == node.name) {
|
||||
node.thedef = parent.label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!node.thedef) {
|
||||
var s = node.start;
|
||||
js_error("Undefined label " + node.name, s.file, s.line, s.col, s.pos);
|
||||
}
|
||||
}
|
||||
}));
|
||||
return ast;
|
||||
};
|
||||
|
||||
|
||||
184
lib/output.js
184
lib/output.js
@@ -173,7 +173,7 @@ function OutputStream(options) {
|
||||
default:
|
||||
return dq > sq ? quote_single() : quote_double();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function encode_string(str, quote) {
|
||||
var ret = make_string(str, quote);
|
||||
@@ -183,20 +183,21 @@ function OutputStream(options) {
|
||||
ret = ret.replace(/--\x3e/g, "--\\x3e");
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
function make_name(name) {
|
||||
name = name.toString();
|
||||
name = to_utf8(name, true);
|
||||
return name;
|
||||
};
|
||||
}
|
||||
|
||||
function make_indent(back) {
|
||||
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
|
||||
};
|
||||
}
|
||||
|
||||
/* -----[ beautification/minification ]----- */
|
||||
|
||||
var has_parens = false;
|
||||
var might_need_space = false;
|
||||
var might_need_semicolon = false;
|
||||
var might_add_newline = 0;
|
||||
@@ -280,7 +281,7 @@ function OutputStream(options) {
|
||||
might_need_semicolon = false;
|
||||
|
||||
if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
|
||||
if (options.semicolons || requireSemicolonChars(ch)) {
|
||||
if (options.semicolons || requireSemicolonChars[ch]) {
|
||||
OUTPUT += ";";
|
||||
current_col++;
|
||||
current_pos++;
|
||||
@@ -340,6 +341,7 @@ function OutputStream(options) {
|
||||
}
|
||||
|
||||
OUTPUT += str;
|
||||
has_parens = str[str.length - 1] == "(";
|
||||
current_pos += str.length;
|
||||
var a = str.split(/\r?\n/), n = a.length - 1;
|
||||
current_line += n;
|
||||
@@ -349,7 +351,7 @@ function OutputStream(options) {
|
||||
current_col = a[n].length;
|
||||
}
|
||||
last = str;
|
||||
};
|
||||
}
|
||||
|
||||
var space = options.beautify ? function() {
|
||||
print(" ");
|
||||
@@ -372,6 +374,11 @@ function OutputStream(options) {
|
||||
return ret;
|
||||
} : function(col, cont) { return cont() };
|
||||
|
||||
var may_add_newline = options.max_line_len ? function() {
|
||||
ensure_line_len();
|
||||
might_add_newline = OUTPUT.length;
|
||||
} : noop;
|
||||
|
||||
var newline = options.beautify ? function() {
|
||||
if (newline_insert < 0) return print("\n");
|
||||
if (OUTPUT[newline_insert] != "\n") {
|
||||
@@ -380,10 +387,7 @@ function OutputStream(options) {
|
||||
current_line++;
|
||||
}
|
||||
newline_insert++;
|
||||
} : options.max_line_len ? function() {
|
||||
ensure_line_len();
|
||||
might_add_newline = OUTPUT.length;
|
||||
} : noop;
|
||||
} : may_add_newline;
|
||||
|
||||
var semicolon = options.beautify ? function() {
|
||||
print(";");
|
||||
@@ -394,11 +398,11 @@ function OutputStream(options) {
|
||||
function force_semicolon() {
|
||||
might_need_semicolon = false;
|
||||
print(";");
|
||||
};
|
||||
}
|
||||
|
||||
function next_indent() {
|
||||
return indentation + options.indent_level;
|
||||
};
|
||||
}
|
||||
|
||||
function with_block(cont) {
|
||||
var ret;
|
||||
@@ -410,34 +414,40 @@ function OutputStream(options) {
|
||||
indent();
|
||||
print("}");
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
function with_parens(cont) {
|
||||
print("(");
|
||||
may_add_newline();
|
||||
//XXX: still nice to have that for argument lists
|
||||
//var ret = with_indent(current_col, cont);
|
||||
var ret = cont();
|
||||
may_add_newline();
|
||||
print(")");
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
function with_square(cont) {
|
||||
print("[");
|
||||
may_add_newline();
|
||||
//var ret = with_indent(current_col, cont);
|
||||
var ret = cont();
|
||||
may_add_newline();
|
||||
print("]");
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
function comma() {
|
||||
may_add_newline();
|
||||
print(",");
|
||||
may_add_newline();
|
||||
space();
|
||||
};
|
||||
}
|
||||
|
||||
function colon() {
|
||||
print(":");
|
||||
space();
|
||||
};
|
||||
}
|
||||
|
||||
var add_mapping = mappings ? function(token, name) {
|
||||
mapping_token = token;
|
||||
@@ -449,7 +459,7 @@ function OutputStream(options) {
|
||||
ensure_line_len();
|
||||
}
|
||||
return OUTPUT;
|
||||
};
|
||||
}
|
||||
|
||||
function has_nlb() {
|
||||
var index = OUTPUT.lastIndexOf("\n");
|
||||
@@ -576,7 +586,7 @@ function OutputStream(options) {
|
||||
indentation : function() { return indentation },
|
||||
current_width : function() { return current_col - indentation },
|
||||
should_break : function() { return options.width && this.current_width() >= options.width },
|
||||
has_parens : function() { return OUTPUT.slice(-1) == "(" },
|
||||
has_parens : function() { return has_parens },
|
||||
newline : newline,
|
||||
print : print,
|
||||
space : space,
|
||||
@@ -617,8 +627,7 @@ function OutputStream(options) {
|
||||
return stack[stack.length - 2 - (n || 0)];
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/* -----[ code generators ]----- */
|
||||
|
||||
@@ -628,7 +637,7 @@ function OutputStream(options) {
|
||||
|
||||
function DEFPRINT(nodetype, generator) {
|
||||
nodetype.DEFMETHOD("_codegen", generator);
|
||||
};
|
||||
}
|
||||
|
||||
var in_directive = false;
|
||||
var active_scope = null;
|
||||
@@ -677,7 +686,7 @@ function OutputStream(options) {
|
||||
} else {
|
||||
nodetype.DEFMETHOD("needs_parens", func);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PARENS(AST_Node, return_false);
|
||||
|
||||
@@ -863,7 +872,7 @@ function OutputStream(options) {
|
||||
}
|
||||
});
|
||||
in_directive = false;
|
||||
};
|
||||
}
|
||||
|
||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
|
||||
force_statement(this.body, output);
|
||||
@@ -899,7 +908,7 @@ function OutputStream(options) {
|
||||
display_body(self.body, false, output, allow_directives);
|
||||
});
|
||||
} else print_braced_empty(self, output);
|
||||
};
|
||||
}
|
||||
DEFPRINT(AST_BlockStatement, function(self, output){
|
||||
print_braced(self, output);
|
||||
});
|
||||
@@ -1062,7 +1071,7 @@ function OutputStream(options) {
|
||||
else break;
|
||||
}
|
||||
force_statement(self.body, output);
|
||||
};
|
||||
}
|
||||
DEFPRINT(AST_If, function(self, output){
|
||||
output.print("if");
|
||||
output.space();
|
||||
@@ -1182,7 +1191,7 @@ function OutputStream(options) {
|
||||
}
|
||||
}));
|
||||
node.print(output, parens);
|
||||
};
|
||||
}
|
||||
|
||||
DEFPRINT(AST_VarDef, function(self, output){
|
||||
self.name.print(output);
|
||||
@@ -1244,7 +1253,7 @@ function OutputStream(options) {
|
||||
var expr = self.expression;
|
||||
expr.print(output);
|
||||
var prop = self.property;
|
||||
if (output.option("ie8") && RESERVED_WORDS(prop)) {
|
||||
if (output.option("ie8") && RESERVED_WORDS[prop]) {
|
||||
output.print("[");
|
||||
output.add_mapping(self.end);
|
||||
output.print_string(prop);
|
||||
@@ -1356,7 +1365,7 @@ function OutputStream(options) {
|
||||
output.print_string(key);
|
||||
} else if ("" + +key == key && key >= 0) {
|
||||
output.print(make_num(key));
|
||||
} else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) {
|
||||
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||
if (quote && output.option("keep_quoted_props")) {
|
||||
output.print_string(key, quote);
|
||||
} else {
|
||||
@@ -1428,7 +1437,7 @@ function OutputStream(options) {
|
||||
else
|
||||
stat.print(output);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// self should be AST_New. decide if we want to show parens or not.
|
||||
function need_constructor_parens(self, output) {
|
||||
@@ -1436,7 +1445,7 @@ function OutputStream(options) {
|
||||
if (self.args.length > 0) return true;
|
||||
|
||||
return output.option("beautify");
|
||||
};
|
||||
}
|
||||
|
||||
function best_of(a) {
|
||||
var best = a[0], len = best.length;
|
||||
@@ -1447,27 +1456,31 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
return best;
|
||||
};
|
||||
}
|
||||
|
||||
function make_num(num) {
|
||||
var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
|
||||
var str = num.toString(10).replace(/^0\./, ".").replace("e+", "e");
|
||||
var candidates = [ str ];
|
||||
if (Math.floor(num) === num) {
|
||||
if (num >= 0) {
|
||||
a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
|
||||
"0" + num.toString(8)); // same.
|
||||
if (num < 0) {
|
||||
candidates.push("-0x" + (-num).toString(16).toLowerCase());
|
||||
} else {
|
||||
a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
|
||||
"-0" + (-num).toString(8)); // same.
|
||||
candidates.push("0x" + num.toString(16).toLowerCase());
|
||||
}
|
||||
if ((m = /^(.*?)(0+)$/.exec(num))) {
|
||||
a.push(m[1] + "e" + m[2].length);
|
||||
}
|
||||
} else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
|
||||
a.push(m[2] + "e-" + (m[1].length + m[2].length),
|
||||
str.substr(str.indexOf(".")));
|
||||
}
|
||||
return best_of(a);
|
||||
};
|
||||
var match, len, digits;
|
||||
if (match = /^\.0+/.exec(str)) {
|
||||
len = match[0].length;
|
||||
digits = str.slice(len);
|
||||
candidates.push(digits + "e-" + (digits.length + len - 1));
|
||||
} else if (match = /0+$/.exec(str)) {
|
||||
len = match[0].length;
|
||||
candidates.push(str.slice(0, -len) + "e" + len);
|
||||
} else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) {
|
||||
candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length));
|
||||
}
|
||||
return best_of(candidates);
|
||||
}
|
||||
|
||||
function make_block(stmt, output) {
|
||||
if (!stmt || stmt instanceof AST_EmptyStatement)
|
||||
@@ -1479,52 +1492,57 @@ function OutputStream(options) {
|
||||
stmt.print(output);
|
||||
output.newline();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/* -----[ source map generators ]----- */
|
||||
|
||||
function DEFMAP(nodetype, generator) {
|
||||
nodetype.DEFMETHOD("add_source_map", function(stream){
|
||||
generator(this, stream);
|
||||
nodetype.forEach(function(nodetype) {
|
||||
nodetype.DEFMETHOD("add_source_map", generator);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// We could easily add info for ALL nodes, but it seems to me that
|
||||
// would be quite wasteful, hence this noop in the base class.
|
||||
DEFMAP(AST_Node, noop);
|
||||
|
||||
function basic_sourcemap_gen(self, output) {
|
||||
output.add_mapping(self.start);
|
||||
};
|
||||
DEFMAP([
|
||||
// We could easily add info for ALL nodes, but it seems to me that
|
||||
// would be quite wasteful, hence this noop in the base class.
|
||||
AST_Node,
|
||||
// since the label symbol will mark it
|
||||
AST_LabeledStatement,
|
||||
AST_Toplevel,
|
||||
], noop);
|
||||
|
||||
// XXX: I'm not exactly sure if we need it for all of these nodes,
|
||||
// or if we should add even more.
|
||||
|
||||
DEFMAP(AST_Directive, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Debugger, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Symbol, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Jump, basic_sourcemap_gen);
|
||||
DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
|
||||
DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it
|
||||
DEFMAP(AST_Lambda, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Switch, basic_sourcemap_gen);
|
||||
DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
|
||||
DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Toplevel, noop);
|
||||
DEFMAP(AST_New, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Try, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Catch, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Finally, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Definitions, basic_sourcemap_gen);
|
||||
DEFMAP(AST_Constant, basic_sourcemap_gen);
|
||||
DEFMAP(AST_ObjectSetter, function(self, output){
|
||||
output.add_mapping(self.start, self.key.name);
|
||||
});
|
||||
DEFMAP(AST_ObjectGetter, function(self, output){
|
||||
output.add_mapping(self.start, self.key.name);
|
||||
});
|
||||
DEFMAP(AST_ObjectProperty, function(self, output){
|
||||
output.add_mapping(self.start, self.key);
|
||||
DEFMAP([
|
||||
AST_Array,
|
||||
AST_BlockStatement,
|
||||
AST_Catch,
|
||||
AST_Constant,
|
||||
AST_Debugger,
|
||||
AST_Definitions,
|
||||
AST_Directive,
|
||||
AST_Finally,
|
||||
AST_Jump,
|
||||
AST_Lambda,
|
||||
AST_New,
|
||||
AST_Object,
|
||||
AST_StatementWithBody,
|
||||
AST_Symbol,
|
||||
AST_Switch,
|
||||
AST_SwitchBranch,
|
||||
AST_Try,
|
||||
], function(output) {
|
||||
output.add_mapping(this.start);
|
||||
});
|
||||
|
||||
DEFMAP([
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectSetter,
|
||||
], function(output) {
|
||||
output.add_mapping(this.start, this.key.name);
|
||||
});
|
||||
|
||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
||||
output.add_mapping(this.start, this.key);
|
||||
});
|
||||
})();
|
||||
|
||||
46
lib/parse.js
46
lib/parse.js
@@ -165,7 +165,7 @@ function is_unicode_connector_punctuation(ch) {
|
||||
};
|
||||
|
||||
function is_identifier(name) {
|
||||
return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
|
||||
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
|
||||
};
|
||||
|
||||
function is_identifier_start(code) {
|
||||
@@ -245,7 +245,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
var ch = S.text.charAt(S.pos++);
|
||||
if (signal_eof && !ch)
|
||||
throw EX_EOF;
|
||||
if (NEWLINE_CHARS(ch)) {
|
||||
if (NEWLINE_CHARS[ch]) {
|
||||
S.newline_before = S.newline_before || !in_string;
|
||||
++S.line;
|
||||
S.col = 0;
|
||||
@@ -272,7 +272,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
var text = S.text;
|
||||
for (var i = S.pos, n = S.text.length; i < n; ++i) {
|
||||
var ch = text[i];
|
||||
if (NEWLINE_CHARS(ch))
|
||||
if (NEWLINE_CHARS[ch])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
@@ -292,9 +292,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
var prev_was_dot = false;
|
||||
function token(type, value, is_comment) {
|
||||
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
|
||||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
|
||||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
|
||||
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX[value]) ||
|
||||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]) ||
|
||||
(type == "punc" && PUNC_BEFORE_EXPRESSION[value]));
|
||||
if (type == "punc" && value == ".") {
|
||||
prev_was_dot = true;
|
||||
} else if (!is_comment) {
|
||||
@@ -324,7 +324,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
};
|
||||
|
||||
function skip_whitespace() {
|
||||
while (WHITESPACE_CHARS(peek()))
|
||||
while (WHITESPACE_CHARS[peek()])
|
||||
next();
|
||||
};
|
||||
|
||||
@@ -424,7 +424,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
for (;;) {
|
||||
var ch = next(true, true);
|
||||
if (ch == "\\") ch = read_escaped_char(true);
|
||||
else if (NEWLINE_CHARS(ch)) parse_error("Unterminated string constant");
|
||||
else if (NEWLINE_CHARS[ch]) parse_error("Unterminated string constant");
|
||||
else if (ch == quote) break;
|
||||
ret += ch;
|
||||
}
|
||||
@@ -476,7 +476,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
backslash = false;
|
||||
}
|
||||
}
|
||||
if (KEYWORDS(name) && escaped) {
|
||||
if (KEYWORDS[name] && escaped) {
|
||||
hex = name.charCodeAt(0).toString(16).toUpperCase();
|
||||
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
|
||||
}
|
||||
@@ -485,7 +485,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
|
||||
var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
|
||||
var prev_backslash = false, ch, in_class = false;
|
||||
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
||||
while ((ch = next(true))) if (NEWLINE_CHARS[ch]) {
|
||||
parse_error("Unexpected line terminator");
|
||||
} else if (prev_backslash) {
|
||||
source += "\\" + ch;
|
||||
@@ -517,7 +517,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
function grow(op) {
|
||||
if (!peek()) return op;
|
||||
var bigger = op + peek();
|
||||
if (OPERATORS(bigger)) {
|
||||
if (OPERATORS[bigger]) {
|
||||
next();
|
||||
return grow(bigger);
|
||||
} else {
|
||||
@@ -550,9 +550,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
function read_word() {
|
||||
var word = read_name();
|
||||
if (prev_was_dot) return token("name", word);
|
||||
return KEYWORDS_ATOM(word) ? token("atom", word)
|
||||
: !KEYWORDS(word) ? token("name", word)
|
||||
: OPERATORS(word) ? token("operator", word)
|
||||
return KEYWORDS_ATOM[word] ? token("atom", word)
|
||||
: !KEYWORDS[word] ? token("name", word)
|
||||
: OPERATORS[word] ? token("operator", word)
|
||||
: token("keyword", word);
|
||||
};
|
||||
|
||||
@@ -603,8 +603,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
}
|
||||
}
|
||||
if (is_digit(code)) return read_num();
|
||||
if (PUNC_CHARS(ch)) return token("punc", next());
|
||||
if (OPERATOR_CHARS(ch)) return read_operator();
|
||||
if (PUNC_CHARS[ch]) return token("punc", next());
|
||||
if (OPERATOR_CHARS[ch]) return read_operator();
|
||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
||||
break;
|
||||
}
|
||||
@@ -969,7 +969,9 @@ function parse($TEXT, options) {
|
||||
|
||||
function labeled_statement() {
|
||||
var label = as_symbol(AST_Label);
|
||||
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
|
||||
if (!all(S.labels, function(l) {
|
||||
return l.name != label.name;
|
||||
})) {
|
||||
// ECMA-262, 12.12: An ECMAScript program is considered
|
||||
// syntactically incorrect if it contains a
|
||||
// LabelledStatement that is enclosed by a
|
||||
@@ -1319,7 +1321,7 @@ function parse($TEXT, options) {
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
}
|
||||
if (ATOMIC_START_TOKEN(S.token.type)) {
|
||||
if (ATOMIC_START_TOKEN[S.token.type]) {
|
||||
return subscripts(as_atom_node(), allow_calls);
|
||||
}
|
||||
unexpected();
|
||||
@@ -1404,7 +1406,7 @@ function parse($TEXT, options) {
|
||||
var tmp = S.token;
|
||||
switch (tmp.type) {
|
||||
case "operator":
|
||||
if (!KEYWORDS(tmp.value)) unexpected();
|
||||
if (!KEYWORDS[tmp.value]) unexpected();
|
||||
case "num":
|
||||
case "string":
|
||||
case "name":
|
||||
@@ -1502,7 +1504,7 @@ function parse($TEXT, options) {
|
||||
|
||||
var maybe_unary = function(allow_calls) {
|
||||
var start = S.token;
|
||||
if (is("operator") && UNARY_PREFIX(start.value)) {
|
||||
if (is("operator") && UNARY_PREFIX[start.value]) {
|
||||
next();
|
||||
handle_regexp();
|
||||
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
|
||||
@@ -1511,7 +1513,7 @@ function parse($TEXT, options) {
|
||||
return ex;
|
||||
}
|
||||
var val = expr_atom(allow_calls);
|
||||
while (is("operator") && UNARY_POSTFIX(S.token.value) && !has_newline_before(S.token)) {
|
||||
while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
|
||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||
val.start = start;
|
||||
val.end = S.token;
|
||||
@@ -1583,7 +1585,7 @@ function parse($TEXT, options) {
|
||||
var maybe_assign = function(no_in) {
|
||||
var start = S.token;
|
||||
var left = maybe_conditional(no_in), val = S.token.value;
|
||||
if (is("operator") && ASSIGNMENT(val)) {
|
||||
if (is("operator") && ASSIGNMENT[val]) {
|
||||
if (is_assignable(left)) {
|
||||
next();
|
||||
return new AST_Assign({
|
||||
|
||||
@@ -150,6 +150,10 @@ function mangle_properties(ast, options) {
|
||||
else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
else if (node instanceof AST_Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
addStrings(node.args[1], add);
|
||||
}
|
||||
}));
|
||||
|
||||
// step 2: transform the tree, renaming properties
|
||||
@@ -167,6 +171,10 @@ function mangle_properties(ast, options) {
|
||||
else if (!options.keep_quoted && node instanceof AST_Sub) {
|
||||
node.property = mangleStrings(node.property);
|
||||
}
|
||||
else if (node instanceof AST_Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
node.args[1] = mangleStrings(node.args[1]);
|
||||
}
|
||||
}));
|
||||
|
||||
// only function declarations after this line
|
||||
|
||||
93
lib/scope.js
93
lib/scope.js
@@ -55,7 +55,7 @@ function SymbolDef(scope, orig, init) {
|
||||
this.mangled_name = null;
|
||||
this.undeclared = false;
|
||||
this.id = SymbolDef.next_id++;
|
||||
};
|
||||
}
|
||||
|
||||
SymbolDef.next_id = 1;
|
||||
|
||||
@@ -63,12 +63,12 @@ SymbolDef.prototype = {
|
||||
unmangleable: function(options) {
|
||||
if (!options) options = {};
|
||||
|
||||
return (this.global && !options.toplevel)
|
||||
return this.global && !options.toplevel
|
||||
|| this.undeclared
|
||||
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
||||
|| (options.keep_fnames
|
||||
|| !options.eval && this.scope.pinned()
|
||||
|| options.keep_fnames
|
||||
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||
|| this.orig[0] instanceof AST_SymbolDefun));
|
||||
|| this.orig[0] instanceof AST_SymbolDefun);
|
||||
},
|
||||
mangle: function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
@@ -100,7 +100,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
// pass 1: setup scope chaining and handle definitions
|
||||
var self = this;
|
||||
var scope = self.parent_scope = null;
|
||||
var labels = new Dictionary();
|
||||
var defun = null;
|
||||
var tw = new TreeWalker(function(node, descend){
|
||||
if (node instanceof AST_Catch) {
|
||||
@@ -115,25 +114,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
node.init_scope_vars(scope);
|
||||
var save_scope = scope;
|
||||
var save_defun = defun;
|
||||
var save_labels = labels;
|
||||
defun = scope = node;
|
||||
labels = new Dictionary();
|
||||
descend();
|
||||
scope = save_scope;
|
||||
defun = save_defun;
|
||||
labels = save_labels;
|
||||
return true; // don't descend again in TreeWalker
|
||||
}
|
||||
if (node instanceof AST_LabeledStatement) {
|
||||
var l = node.label;
|
||||
if (labels.has(l.name)) {
|
||||
throw new Error(string_template("Label {name} defined twice", l));
|
||||
}
|
||||
labels.set(l.name, l);
|
||||
descend();
|
||||
labels.del(l.name);
|
||||
return true; // no descend again
|
||||
}
|
||||
if (node instanceof AST_With) {
|
||||
for (var s = scope; s; s = s.parent_scope)
|
||||
s.uses_with = true;
|
||||
@@ -171,15 +157,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
else if (node instanceof AST_SymbolCatch) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
}
|
||||
else if (node instanceof AST_LabelRef) {
|
||||
var sym = labels.get(node.name);
|
||||
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
|
||||
name: node.name,
|
||||
line: node.start.line,
|
||||
col: node.start.col
|
||||
}));
|
||||
node.thedef = sym;
|
||||
}
|
||||
});
|
||||
self.walk(tw);
|
||||
|
||||
@@ -367,7 +344,7 @@ function next_mangled_name(scope, options, def) {
|
||||
}
|
||||
while (true) {
|
||||
name = base54(++scope.cname);
|
||||
if (in_use[name] || !is_identifier(name) || member(name, options.reserved)) continue;
|
||||
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue;
|
||||
if (!names[name]) break;
|
||||
holes.push(scope.cname);
|
||||
}
|
||||
@@ -378,7 +355,7 @@ function next_mangled_name(scope, options, def) {
|
||||
return name;
|
||||
}
|
||||
|
||||
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||
AST_Symbol.DEFMETHOD("unmangleable", function(options) {
|
||||
var def = this.definition();
|
||||
return !def || def.unmangleable(options);
|
||||
});
|
||||
@@ -386,16 +363,15 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||
// labels are always mangleable
|
||||
AST_Label.DEFMETHOD("unmangleable", return_false);
|
||||
|
||||
AST_Symbol.DEFMETHOD("unreferenced", function(){
|
||||
return this.definition().references.length == 0
|
||||
&& !(this.scope.uses_eval || this.scope.uses_with);
|
||||
AST_Symbol.DEFMETHOD("unreferenced", function() {
|
||||
return !this.definition().references.length && !this.scope.pinned();
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("definition", function(){
|
||||
AST_Symbol.DEFMETHOD("definition", function() {
|
||||
return this.thedef;
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("global", function(){
|
||||
AST_Symbol.DEFMETHOD("global", function() {
|
||||
return this.definition().global;
|
||||
});
|
||||
|
||||
@@ -410,6 +386,7 @@ function _default_mangler_options(options) {
|
||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||
// Never mangle arguments
|
||||
push_uniq(options.reserved, "arguments");
|
||||
options.reserved.has = makePredicate(options.reserved);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -457,24 +434,26 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
var redef = def.redefined();
|
||||
if (redef) {
|
||||
redefined.push(def);
|
||||
def.references.forEach(function(ref) {
|
||||
ref.thedef = redef;
|
||||
ref.reference(options);
|
||||
ref.thedef = def;
|
||||
});
|
||||
reference(node.argname);
|
||||
def.references.forEach(reference);
|
||||
}
|
||||
descend();
|
||||
if (!redef) mangle(def);
|
||||
return true;
|
||||
}
|
||||
|
||||
function reference(sym) {
|
||||
sym.thedef = redef;
|
||||
sym.reference(options);
|
||||
sym.thedef = def;
|
||||
}
|
||||
});
|
||||
this.walk(tw);
|
||||
redefined.forEach(mangle);
|
||||
|
||||
function mangle(def) {
|
||||
if (!member(def.name, options.reserved)) {
|
||||
def.mangle(options);
|
||||
}
|
||||
if (options.reserved.has[def.name]) return;
|
||||
def.mangle(options);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -524,7 +503,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
function rename(def) {
|
||||
if (def.global && options.cache) return;
|
||||
if (def.unmangleable(options)) return;
|
||||
if (member(def.name, options.reserved)) return;
|
||||
if (options.reserved.has[def.name]) return;
|
||||
var d = def.redefined();
|
||||
def.name = d ? d.name : next_name();
|
||||
def.orig.forEach(function(sym) {
|
||||
@@ -576,17 +555,21 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||
});
|
||||
|
||||
var base54 = (function() {
|
||||
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
|
||||
var digits = "0123456789".split("");
|
||||
var freq = Object.create(null);
|
||||
function init(chars) {
|
||||
var array = [];
|
||||
for (var i = 0, len = chars.length; i < len; i++) {
|
||||
var ch = chars[i];
|
||||
array.push(ch);
|
||||
freq[ch] = -1e-2 * i;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
var digits = init("0123456789");
|
||||
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
|
||||
var chars, frequency;
|
||||
function reset() {
|
||||
frequency = Object.create(null);
|
||||
leading.forEach(function(ch) {
|
||||
frequency[ch] = 0;
|
||||
});
|
||||
digits.forEach(function(ch) {
|
||||
frequency[ch] = 0;
|
||||
});
|
||||
frequency = Object.create(freq);
|
||||
}
|
||||
base54.consider = function(str, delta) {
|
||||
for (var i = str.length; --i >= 0;) {
|
||||
@@ -597,7 +580,7 @@ var base54 = (function() {
|
||||
return frequency[b] - frequency[a];
|
||||
}
|
||||
base54.sort = function() {
|
||||
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
||||
chars = leading.sort(compare).concat(digits.sort(compare));
|
||||
};
|
||||
base54.reset = reset;
|
||||
reset();
|
||||
@@ -611,6 +594,6 @@ var base54 = (function() {
|
||||
base = 64;
|
||||
} while (num > 0);
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
return base54;
|
||||
})();
|
||||
|
||||
@@ -57,26 +57,26 @@ function SourceMap(options) {
|
||||
file : options.file,
|
||||
sourceRoot : options.root
|
||||
});
|
||||
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
||||
|
||||
if (orig_map && Array.isArray(options.orig.sources)) {
|
||||
orig_map._sources.toArray().forEach(function(source) {
|
||||
var sourceContent = orig_map.sourceContentFor(source, true);
|
||||
if (sourceContent) {
|
||||
generator.setSourceContent(source, sourceContent);
|
||||
}
|
||||
});
|
||||
var maps = options.orig && Object.create(null);
|
||||
if (maps) for (var source in options.orig) {
|
||||
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
|
||||
if (Array.isArray(options.orig[source].sources)) {
|
||||
map._sources.toArray().forEach(function(source) {
|
||||
var sourceContent = map.sourceContentFor(source, true);
|
||||
if (sourceContent) generator.setSourceContent(source, sourceContent);
|
||||
});
|
||||
}
|
||||
maps[source] = map;
|
||||
}
|
||||
|
||||
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||
if (orig_map) {
|
||||
var info = orig_map.originalPositionFor({
|
||||
var map = maps && maps[source];
|
||||
if (map) {
|
||||
var info = map.originalPositionFor({
|
||||
line: orig_line,
|
||||
column: orig_col
|
||||
});
|
||||
if (info.source === null) {
|
||||
return;
|
||||
}
|
||||
if (info.source === null) return;
|
||||
source = info.source;
|
||||
orig_line = info.line;
|
||||
orig_col = info.column;
|
||||
|
||||
@@ -93,7 +93,12 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
|
||||
_(AST_DWLoop, function(self, tw){
|
||||
_(AST_Do, function(self, tw){
|
||||
self.body = self.body.transform(tw);
|
||||
self.condition = self.condition.transform(tw);
|
||||
});
|
||||
|
||||
_(AST_While, function(self, tw){
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
149
lib/utils.js
149
lib/utils.js
@@ -45,27 +45,25 @@
|
||||
|
||||
function characters(str) {
|
||||
return str.split("");
|
||||
};
|
||||
}
|
||||
|
||||
function member(name, array) {
|
||||
return array.indexOf(name) >= 0;
|
||||
};
|
||||
}
|
||||
|
||||
function find_if(func, array) {
|
||||
for (var i = 0, n = array.length; i < n; ++i) {
|
||||
if (func(array[i]))
|
||||
return array[i];
|
||||
if (func(array[i])) return array[i];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function repeat_string(str, i) {
|
||||
if (i <= 0) return "";
|
||||
if (i == 1) return str;
|
||||
var d = repeat_string(str, i >> 1);
|
||||
d += d;
|
||||
if (i & 1) d += str;
|
||||
return d;
|
||||
};
|
||||
return i & 1 ? d + str : d;
|
||||
}
|
||||
|
||||
function configure_error_stack(fn) {
|
||||
Object.defineProperty(fn.prototype, "stack", {
|
||||
@@ -84,27 +82,23 @@ function configure_error_stack(fn) {
|
||||
function DefaultsError(msg, defs) {
|
||||
this.message = msg;
|
||||
this.defs = defs;
|
||||
};
|
||||
}
|
||||
DefaultsError.prototype = Object.create(Error.prototype);
|
||||
DefaultsError.prototype.constructor = DefaultsError;
|
||||
DefaultsError.prototype.name = "DefaultsError";
|
||||
configure_error_stack(DefaultsError);
|
||||
|
||||
DefaultsError.croak = function(msg, defs) {
|
||||
throw new DefaultsError(msg, defs);
|
||||
};
|
||||
|
||||
function defaults(args, defs, croak) {
|
||||
if (args === true)
|
||||
args = {};
|
||||
if (args === true) args = {};
|
||||
var ret = args || {};
|
||||
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i))
|
||||
DefaultsError.croak("`" + i + "` is not a supported option", defs);
|
||||
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
|
||||
throw new DefaultsError("`" + i + "` is not a supported option", defs);
|
||||
}
|
||||
for (var i in defs) if (HOP(defs, i)) {
|
||||
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
function merge(obj, ext) {
|
||||
var count = 0;
|
||||
@@ -113,7 +107,7 @@ function merge(obj, ext) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
function return_false() { return false; }
|
||||
@@ -145,7 +139,7 @@ var MAP = (function(){
|
||||
}
|
||||
return is_last;
|
||||
};
|
||||
if (a instanceof Array) {
|
||||
if (Array.isArray(a)) {
|
||||
if (backwards) {
|
||||
for (i = a.length; --i >= 0;) if (doit()) break;
|
||||
ret.reverse();
|
||||
@@ -172,101 +166,40 @@ var MAP = (function(){
|
||||
function push_uniq(array, el) {
|
||||
if (array.indexOf(el) < 0)
|
||||
array.push(el);
|
||||
};
|
||||
}
|
||||
|
||||
function string_template(text, props) {
|
||||
return text.replace(/\{(.+?)\}/g, function(str, p){
|
||||
return props && props[p];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function remove(array, el) {
|
||||
for (var i = array.length; --i >= 0;) {
|
||||
if (array[i] === el) array.splice(i, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function mergeSort(array, cmp) {
|
||||
if (array.length < 2) return array.slice();
|
||||
function merge(a, b) {
|
||||
var r = [], ai = 0, bi = 0, i = 0;
|
||||
while (ai < a.length && bi < b.length) {
|
||||
cmp(a[ai], b[bi]) <= 0
|
||||
? r[i++] = a[ai++]
|
||||
: r[i++] = b[bi++];
|
||||
}
|
||||
if (ai < a.length) r.push.apply(r, a.slice(ai));
|
||||
if (bi < b.length) r.push.apply(r, b.slice(bi));
|
||||
return r;
|
||||
};
|
||||
function _ms(a) {
|
||||
if (a.length <= 1)
|
||||
return a;
|
||||
var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
|
||||
left = _ms(left);
|
||||
right = _ms(right);
|
||||
return merge(left, right);
|
||||
};
|
||||
return _ms(array);
|
||||
};
|
||||
|
||||
// this function is taken from Acorn [1], written by Marijn Haverbeke
|
||||
// [1] https://github.com/marijnh/acorn
|
||||
function makePredicate(words) {
|
||||
if (!(words instanceof Array)) words = words.split(" ");
|
||||
var f = "", cats = [];
|
||||
out: for (var i = 0; i < words.length; ++i) {
|
||||
for (var j = 0; j < cats.length; ++j)
|
||||
if (cats[j][0].length == words[i].length) {
|
||||
cats[j].push(words[i]);
|
||||
continue out;
|
||||
}
|
||||
cats.push([words[i]]);
|
||||
}
|
||||
function quote(word) {
|
||||
return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
|
||||
switch (s) {
|
||||
case "\u2028": return "\\u2028";
|
||||
case "\u2029": return "\\u2029";
|
||||
}
|
||||
return s;
|
||||
});
|
||||
}
|
||||
function compareTo(arr) {
|
||||
if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
|
||||
f += "switch(str){";
|
||||
for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
|
||||
f += "return true}return false;";
|
||||
}
|
||||
// When there are more than three length categories, an outer
|
||||
// switch first dispatches on the lengths, to save on comparisons.
|
||||
if (cats.length > 3) {
|
||||
cats.sort(function(a, b) {return b.length - a.length;});
|
||||
f += "switch(str.length){";
|
||||
for (var i = 0; i < cats.length; ++i) {
|
||||
var cat = cats[i];
|
||||
f += "case " + cat[0].length + ":";
|
||||
compareTo(cat);
|
||||
}
|
||||
f += "}";
|
||||
// Otherwise, simply generate a flat `switch` statement.
|
||||
} else {
|
||||
compareTo(words);
|
||||
}
|
||||
return new Function("str", f);
|
||||
};
|
||||
if (!Array.isArray(words)) words = words.split(" ");
|
||||
var map = Object.create(null);
|
||||
words.forEach(function(word) {
|
||||
map[word] = true;
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
function all(array, predicate) {
|
||||
for (var i = array.length; --i >= 0;)
|
||||
if (!predicate(array[i]))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
function Dictionary() {
|
||||
this._values = Object.create(null);
|
||||
this._size = 0;
|
||||
};
|
||||
}
|
||||
Dictionary.prototype = {
|
||||
set: function(key, val) {
|
||||
if (!this.has(key)) ++this._size;
|
||||
@@ -327,20 +260,22 @@ function HOP(obj, prop) {
|
||||
// a statement.
|
||||
function first_in_statement(stack) {
|
||||
var node = stack.parent(-1);
|
||||
for (var i = 0, p; p = stack.parent(i); i++) {
|
||||
if (p instanceof AST_Statement && p.body === node)
|
||||
return true;
|
||||
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
|
||||
(p.TYPE == "Call" && p.expression === node ) ||
|
||||
(p instanceof AST_Dot && p.expression === node ) ||
|
||||
(p instanceof AST_Sub && p.expression === node ) ||
|
||||
(p instanceof AST_Conditional && p.condition === node ) ||
|
||||
(p instanceof AST_Binary && p.left === node ) ||
|
||||
(p instanceof AST_UnaryPostfix && p.expression === node ))
|
||||
{
|
||||
node = p;
|
||||
} else {
|
||||
return false;
|
||||
for (var i = 0, p; p = stack.parent(i++); node = p) {
|
||||
if (p.TYPE == "Call") {
|
||||
if (p.expression === node) continue;
|
||||
} else if (p instanceof AST_Binary) {
|
||||
if (p.left === node) continue;
|
||||
} else if (p instanceof AST_Conditional) {
|
||||
if (p.condition === node) continue;
|
||||
} else if (p instanceof AST_PropAccess) {
|
||||
if (p.expression === node) continue;
|
||||
} else if (p instanceof AST_Sequence) {
|
||||
if (p.expressions[0] === node) continue;
|
||||
} else if (p instanceof AST_Statement) {
|
||||
return p.body === node;
|
||||
} else if (p instanceof AST_UnaryPostfix) {
|
||||
if (p.expression === node) continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.3.16",
|
||||
"version": "3.4.0",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -28,7 +28,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~5.5.3",
|
||||
"mocha": "~3.5.1",
|
||||
"semver": "~5.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -4056,6 +4056,36 @@ replace_all_var: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
replace_all_var_scope: {
|
||||
rename = true;
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
(function(r, a) {
|
||||
switch (~a) {
|
||||
case (b += a):
|
||||
case a++:
|
||||
}
|
||||
})(--b, a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
(function(c, o) {
|
||||
switch (~a) {
|
||||
case (b += a):
|
||||
case o++:
|
||||
}
|
||||
})(--b, a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "100 109"
|
||||
}
|
||||
|
||||
cascade_statement: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -4901,6 +4931,27 @@ collapse_rhs_lhs_2: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
collapse_rhs_loop: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var s;
|
||||
s = "<tpl>PASS</tpl>";
|
||||
for (var m, r = /<tpl>(.*)<\/tpl>/; m = s.match(r);)
|
||||
s = s.replace(m[0], m[1]);
|
||||
console.log(s);
|
||||
}
|
||||
expect: {
|
||||
var s;
|
||||
s = "<tpl>PASS</tpl>";
|
||||
for (var m, r = /<tpl>(.*)<\/tpl>/; m = s.match(r);)
|
||||
s = s.replace(m[0], m[1]);
|
||||
console.log(s);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
collapse_rhs_side_effects: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
@@ -5303,3 +5354,48 @@ issue_2974: {
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3032: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
f: function() {
|
||||
this.a = 42;
|
||||
return [ this.a, !1 ];
|
||||
}
|
||||
}.f()[0]);
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
f: function() {
|
||||
this.a = 42;
|
||||
return [ this.a, !1 ];
|
||||
}
|
||||
}.f()[0]);
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_3096: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
var ar = ["a", "b"];
|
||||
var first = ar.pop();
|
||||
return ar + "" + first;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var ar = ["a", "b"];
|
||||
var first = ar.pop();
|
||||
return ar + "" + first;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "ab"
|
||||
}
|
||||
|
||||
@@ -1814,3 +1814,115 @@ issue_2995: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3146_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(f) {
|
||||
f("g()");
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
function g(b) {
|
||||
if (!b) b = "PASS";
|
||||
console.log(b);
|
||||
}
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(f) {
|
||||
f("g()");
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
function g(b) {
|
||||
if (!b) b = "PASS";
|
||||
console.log(b);
|
||||
}
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3146_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(f) {
|
||||
f("g()");
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
function g(b) {
|
||||
if (!b) b = "PASS";
|
||||
console.log(b);
|
||||
}
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function(f) {
|
||||
f("g()");
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
function g(b) {
|
||||
if (!b) b = "PASS";
|
||||
console.log(b);
|
||||
}
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3146_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var g = "PASS";
|
||||
(function(f) {
|
||||
var g = "FAIL";
|
||||
f("console.log(g)", g[g]);
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
var g = "PASS";
|
||||
(function(f) {
|
||||
var g = "FAIL";
|
||||
f("console.log(g)", g[g]);
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3146_4: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var g = "PASS";
|
||||
(function(f) {
|
||||
var g = "FAIL";
|
||||
f("console.log(g)", g[g]);
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
var g = "PASS";
|
||||
(function(f) {
|
||||
var g = "FAIL";
|
||||
f("console.log(g)", g[g]);
|
||||
})(function(a) {
|
||||
eval(a);
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -2051,3 +2051,271 @@ drop_lone_use_strict: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_3016_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
do {
|
||||
(function(a) {
|
||||
return a[b];
|
||||
var a;
|
||||
})(3);
|
||||
} while (0);
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3016_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
do {
|
||||
(function(a) {
|
||||
return a[b];
|
||||
try {
|
||||
a = 2;
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
})(3);
|
||||
} while (0);
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3016_2_ie8: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
ie8: true,
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
do {
|
||||
(function(a) {
|
||||
return a[b];
|
||||
try {
|
||||
a = 2;
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
})(3);
|
||||
} while (0);
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3016_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log(function() {
|
||||
return a ? "FAIL" : a = "PASS";
|
||||
try {
|
||||
a = 2;
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}());
|
||||
} while (b--);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3016_3_ie8: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
ie8: true,
|
||||
inline: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log(function() {
|
||||
return a ? "FAIL" : a = "PASS";
|
||||
try {
|
||||
a = 2;
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}());
|
||||
} while (b--);
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3018: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1, c = "PASS";
|
||||
do {
|
||||
(function() {
|
||||
(function(a) {
|
||||
a = 0 != (a && (c = "FAIL"));
|
||||
})();
|
||||
})();
|
||||
} while (b--);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var b = 1, c = "PASS";
|
||||
do {
|
||||
a = void 0,
|
||||
a = 0 != (a && (c = "FAIL"));
|
||||
} while (b--);
|
||||
var a;
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3054: {
|
||||
options = {
|
||||
booleans: true,
|
||||
collapse_vars: true,
|
||||
inline: 1,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f() {
|
||||
return { a: true };
|
||||
}
|
||||
console.log(function(b) {
|
||||
b = false;
|
||||
return f();
|
||||
}().a, f.call().a);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f() {
|
||||
return { a: !0 };
|
||||
}
|
||||
console.log(function(b) {
|
||||
return { a: !(b = !1) };
|
||||
}().a, f.call().a);
|
||||
}
|
||||
expect_stdout: "true true"
|
||||
}
|
||||
|
||||
issue_3076: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
inline: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = "PASS";
|
||||
(function(b) {
|
||||
var n = 2;
|
||||
while (--b + function() {
|
||||
e && (c = "FAIL");
|
||||
e = 5;
|
||||
return 1;
|
||||
try {
|
||||
var a = 5;
|
||||
} catch (e) {
|
||||
var e;
|
||||
}
|
||||
}().toString() && --n > 0);
|
||||
})(2);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "PASS";
|
||||
(function(b) {
|
||||
var n = 2;
|
||||
while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1).toString() && --n > 0);
|
||||
var e;
|
||||
})(2),
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3125: {
|
||||
options = {
|
||||
inline: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
return "PASS";
|
||||
}.call());
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -686,3 +686,173 @@ undefined_key: {
|
||||
}
|
||||
expect_stdout: "3"
|
||||
}
|
||||
|
||||
issue_3021: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, b = 2;
|
||||
(function() {
|
||||
b = a;
|
||||
if (a++ + b--)
|
||||
return 1;
|
||||
return;
|
||||
var b = {};
|
||||
})();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, b = 2;
|
||||
(function() {
|
||||
b = a;
|
||||
if (a++ + b--)
|
||||
return 1;
|
||||
return;
|
||||
var b = {};
|
||||
})();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "2 2"
|
||||
}
|
||||
|
||||
issue_3046: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
do {
|
||||
var b = {
|
||||
c: a++
|
||||
};
|
||||
} while (b.c && a);
|
||||
return a;
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
do {
|
||||
var b_c = a++;
|
||||
} while (b_c && a);
|
||||
return a;
|
||||
}(0));
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3071_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
hoist_props: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var obj = {};
|
||||
obj.one = 1;
|
||||
obj.two = 2;
|
||||
console.log(obj.one);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3071_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
hoist_props: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
obj = {};
|
||||
obj.one = 1;
|
||||
obj.two = 2;
|
||||
console.log(obj.one);
|
||||
var obj;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3071_2_toplevel: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
hoist_props: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
obj = {};
|
||||
obj.one = 1;
|
||||
obj.two = 2;
|
||||
console.log(obj.one);
|
||||
var obj;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3071_3: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function(a, b) {
|
||||
(function f(o) {
|
||||
var n = 2;
|
||||
while (--b + (o = {
|
||||
p: c++,
|
||||
}) && --n > 0);
|
||||
})();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function(a, b) {
|
||||
(function f(o) {
|
||||
var n = 2;
|
||||
while (--b + (o = {
|
||||
p: c++,
|
||||
}) && --n > 0);
|
||||
})();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
@@ -464,3 +464,77 @@ issue_2976_2: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3035: {
|
||||
mangle = {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function(a) {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (b) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (a) {
|
||||
b && (c = "PASS");
|
||||
}
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function(o) {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (t) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (o) {
|
||||
t && (c = "PASS");
|
||||
}
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3035_ie8: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function(a) {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (b) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (a) {
|
||||
b && (c = "PASS");
|
||||
}
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function(t) {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (o) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (t) {
|
||||
o && (c = "PASS");
|
||||
}
|
||||
}
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
@@ -1,11 +1,31 @@
|
||||
remove_redundant_sequence_items: {
|
||||
options = { side_effects: true };
|
||||
remove_sequence: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
(0, 1, eval)();
|
||||
(0, 1, logThis)();
|
||||
(0, 1, _decorators.logThis)();
|
||||
}
|
||||
expect: {
|
||||
eval();
|
||||
logThis();
|
||||
(0, _decorators.logThis)();
|
||||
}
|
||||
}
|
||||
|
||||
remove_redundant_sequence_items: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
(0, 1, eval)();
|
||||
(0, 1, logThis)();
|
||||
(0, 1, _decorators.logThis)();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
(0, eval)();
|
||||
logThis();
|
||||
(0, _decorators.logThis)();
|
||||
@@ -13,13 +33,17 @@ remove_redundant_sequence_items: {
|
||||
}
|
||||
|
||||
dont_remove_this_binding_sequence: {
|
||||
options = { side_effects: true };
|
||||
options = {
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
(0, eval)();
|
||||
(0, logThis)();
|
||||
(0, _decorators.logThis)();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
(0, eval)();
|
||||
logThis();
|
||||
(0, _decorators.logThis)();
|
||||
|
||||
@@ -3,8 +3,9 @@ this_binding_conditionals: {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
};
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
(1 && a)();
|
||||
(0 || a)();
|
||||
(0 || 1 && a)();
|
||||
@@ -26,6 +27,7 @@ this_binding_conditionals: {
|
||||
(1 ? eval : 0)();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
a();
|
||||
a();
|
||||
a();
|
||||
@@ -53,13 +55,15 @@ this_binding_collapse_vars: {
|
||||
collapse_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
};
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var c = a; c();
|
||||
var d = a.b; d();
|
||||
var e = eval; e();
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
a();
|
||||
(0, a.b)();
|
||||
(0, eval)();
|
||||
@@ -69,31 +73,88 @@ this_binding_collapse_vars: {
|
||||
this_binding_side_effects: {
|
||||
options = {
|
||||
side_effects : true
|
||||
};
|
||||
}
|
||||
input: {
|
||||
(function (foo) {
|
||||
(function(foo) {
|
||||
(0, foo)();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
(0, eval)("console.log(foo);");
|
||||
}());
|
||||
(function (foo) {
|
||||
(function(foo) {
|
||||
"use strict";
|
||||
(0, foo)();
|
||||
(0, foo.bar)();
|
||||
(0, eval)("console.log(foo);");
|
||||
}());
|
||||
(function(foo) {
|
||||
var eval = console;
|
||||
(0, foo)();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
(0, eval)("console.log(foo);");
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(function (foo) {
|
||||
(function(foo) {
|
||||
foo();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
eval("console.log(foo);");
|
||||
}());
|
||||
(function (foo) {
|
||||
(function(foo) {
|
||||
"use strict";
|
||||
foo();
|
||||
(0, foo.bar)();
|
||||
(0, eval)("console.log(foo);");
|
||||
}());
|
||||
(function(foo) {
|
||||
var eval = console;
|
||||
foo();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
eval("console.log(foo);");
|
||||
}());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this_binding_sequences: {
|
||||
options = {
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
return eval("this");
|
||||
}());
|
||||
console.log(typeof function() {
|
||||
"use strict";
|
||||
return eval("this");
|
||||
}());
|
||||
console.log(typeof function() {
|
||||
return (0, eval)("this");
|
||||
}());
|
||||
console.log(typeof function() {
|
||||
"use strict";
|
||||
return (0, eval)("this");
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
return eval("this");
|
||||
}()),
|
||||
console.log(typeof function() {
|
||||
"use strict";
|
||||
return eval("this");
|
||||
}()),
|
||||
console.log(typeof function() {
|
||||
return eval("this");
|
||||
}()),
|
||||
console.log(typeof function() {
|
||||
"use strict";
|
||||
return (0, eval)("this");
|
||||
}());
|
||||
}
|
||||
expect_stdout: [
|
||||
"object",
|
||||
"undefined",
|
||||
"object",
|
||||
"object",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ too_short: {
|
||||
}
|
||||
}
|
||||
expect_exact: [
|
||||
'function f(a){',
|
||||
'return{',
|
||||
'c:42,',
|
||||
'd:a(),',
|
||||
'e:"foo"}}',
|
||||
"function f(",
|
||||
"a){return{",
|
||||
"c:42,d:a(",
|
||||
'),e:"foo"}',
|
||||
"}",
|
||||
]
|
||||
expect_warnings: [
|
||||
"WARN: Output exceeds 10 characters"
|
||||
"WARN: Output exceeds 10 characters",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -29,11 +29,25 @@ just_enough: {
|
||||
}
|
||||
}
|
||||
expect_exact: [
|
||||
'function f(a){',
|
||||
'return{c:42,',
|
||||
"function f(a){",
|
||||
"return{c:42,",
|
||||
'd:a(),e:"foo"}',
|
||||
'}',
|
||||
]
|
||||
expect_warnings: [
|
||||
"}",
|
||||
]
|
||||
expect_warnings: []
|
||||
}
|
||||
|
||||
issue_304: {
|
||||
beautify = {
|
||||
max_line_len: 10,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0, c = 0, d = 0, e = 0;
|
||||
}
|
||||
expect_exact: [
|
||||
"var a=0,",
|
||||
"b=0,c=0,",
|
||||
"d=0,e=0;",
|
||||
]
|
||||
expect_warnings: []
|
||||
}
|
||||
|
||||
@@ -1,21 +1,49 @@
|
||||
hex_numbers_in_parentheses_for_prototype_functions: {
|
||||
input: {
|
||||
(-2);
|
||||
(-2).toFixed(0);
|
||||
|
||||
(2);
|
||||
(2).toFixed(0);
|
||||
|
||||
(0.2);
|
||||
(0.2).toFixed(0);
|
||||
|
||||
(0.00000002);
|
||||
(0.00000002).toFixed(0);
|
||||
|
||||
(1000000000000000128);
|
||||
(1000000000000000128).toFixed(0);
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);"
|
||||
input: {
|
||||
function f() {
|
||||
(-2);
|
||||
(-2).toFixed(0);
|
||||
|
||||
(2);
|
||||
(2).toFixed(0);
|
||||
|
||||
(0.2);
|
||||
(0.2).toFixed(0);
|
||||
|
||||
(2.34e20);
|
||||
(2.34e20).toFixed(0);
|
||||
|
||||
(0.00000002);
|
||||
(0.00000002).toFixed(0);
|
||||
|
||||
(1000000000000000128);
|
||||
(1000000000000000128).toFixed(0);
|
||||
|
||||
(-1000000000000000128);
|
||||
(-1000000000000000128).toFixed(0);
|
||||
}
|
||||
}
|
||||
expect_exact: [
|
||||
"function f() {",
|
||||
" -2;",
|
||||
" (-2).toFixed(0);",
|
||||
" 2;",
|
||||
" 2..toFixed(0);",
|
||||
" .2;",
|
||||
" .2.toFixed(0);",
|
||||
" 234e18;",
|
||||
" 234e18.toFixed(0);",
|
||||
" 2e-8;",
|
||||
" 2e-8.toFixed(0);",
|
||||
" 0xde0b6b3a7640080;",
|
||||
" (0xde0b6b3a7640080).toFixed(0);",
|
||||
" -0xde0b6b3a7640080;",
|
||||
" (-0xde0b6b3a7640080).toFixed(0);",
|
||||
"}",
|
||||
]
|
||||
}
|
||||
|
||||
comparisons: {
|
||||
|
||||
@@ -1208,6 +1208,37 @@ join_object_assignments_3: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
join_object_assignments_4: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var o;
|
||||
console.log(o);
|
||||
o = {};
|
||||
o.a = "foo";
|
||||
console.log(o.b);
|
||||
o.b = "bar";
|
||||
console.log(o.a);
|
||||
}
|
||||
expect: {
|
||||
var o;
|
||||
console.log(o),
|
||||
o = {
|
||||
a: "foo",
|
||||
},
|
||||
console.log(o.b),
|
||||
o.b = "bar",
|
||||
console.log(o.a);
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"undefined",
|
||||
"foo",
|
||||
]
|
||||
}
|
||||
|
||||
join_object_assignments_return_1: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
@@ -1640,3 +1671,61 @@ issue_2893_2: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_869_1: {
|
||||
mangle = {
|
||||
properties: {
|
||||
reserved: [ "get" ]
|
||||
},
|
||||
}
|
||||
input: {
|
||||
var o = { p: "FAIL" };
|
||||
Object.defineProperty(o, "p", {
|
||||
get: function() {
|
||||
return "PASS";
|
||||
}
|
||||
});
|
||||
console.log(o.p);
|
||||
}
|
||||
expect: {
|
||||
var o = { o: "FAIL" };
|
||||
Object.defineProperty(o, "o", {
|
||||
get: function() {
|
||||
return "PASS";
|
||||
}
|
||||
});
|
||||
console.log(o.o);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_869_2: {
|
||||
mangle = {
|
||||
properties: {
|
||||
reserved: [ "get" ]
|
||||
},
|
||||
}
|
||||
input: {
|
||||
var o = { p: "FAIL" };
|
||||
Object.defineProperties(o, {
|
||||
p: {
|
||||
get: function() {
|
||||
return "PASS";
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log(o.p);
|
||||
}
|
||||
expect: {
|
||||
var o = { o: "FAIL" };
|
||||
Object.defineProperties(o, {
|
||||
o: {
|
||||
get: function() {
|
||||
return "PASS";
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log(o.o);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -535,3 +535,110 @@ issue_2705_6: {
|
||||
"/* */new(/* */a()||b())(c(),d());",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3065_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
pure_funcs: [ "pureFunc" ],
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function modifyWrapper(a, f, wrapper) {
|
||||
wrapper.a = a;
|
||||
wrapper.f = f;
|
||||
return wrapper;
|
||||
}
|
||||
function pureFunc(fun) {
|
||||
return modifyWrapper(1, fun, function(a) {
|
||||
return fun(a);
|
||||
});
|
||||
}
|
||||
var unused = pureFunc(function(x) {
|
||||
return x;
|
||||
});
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_3065_2: {
|
||||
rename = true
|
||||
options = {
|
||||
inline: true,
|
||||
pure_funcs: [ "pureFunc" ],
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {
|
||||
reserved: [ "pureFunc" ],
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function modifyWrapper(a, f, wrapper) {
|
||||
wrapper.a = a;
|
||||
wrapper.f = f;
|
||||
return wrapper;
|
||||
}
|
||||
function pureFunc(fun) {
|
||||
return modifyWrapper(1, fun, function(a) {
|
||||
return fun(a);
|
||||
});
|
||||
}
|
||||
var unused = pureFunc(function(x) {
|
||||
return x;
|
||||
});
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_3065_3: {
|
||||
options = {
|
||||
pure_funcs: [ "debug" ],
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function debug(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
debug(function() {
|
||||
console.log("PASS");
|
||||
return "FAIL";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
issue_3065_4: {
|
||||
options = {
|
||||
pure_funcs: [ "debug" ],
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var debug = function(msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
debug(function() {
|
||||
console.log("PASS");
|
||||
return "FAIL";
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1476,18 +1476,18 @@ defun_redefine: {
|
||||
};
|
||||
return g() + h();
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
function g() {
|
||||
return 1;
|
||||
}
|
||||
g = function() {
|
||||
(function() {
|
||||
return 3;
|
||||
};
|
||||
return g() + 2;
|
||||
});
|
||||
return 3 + 2;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "5"
|
||||
}
|
||||
|
||||
func_inline: {
|
||||
@@ -1527,23 +1527,37 @@ func_modified: {
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
function a() { return 1; }
|
||||
function b() { return 2; }
|
||||
function c() { return 3; }
|
||||
function a() {
|
||||
return 1;
|
||||
}
|
||||
function b() {
|
||||
return 2;
|
||||
}
|
||||
function c() {
|
||||
return 3;
|
||||
}
|
||||
b.inject = [];
|
||||
c = function() { return 4; };
|
||||
c = function() {
|
||||
return 4;
|
||||
};
|
||||
return a() + b() + c();
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
function b() { return 2; }
|
||||
function c() { return 3; }
|
||||
function b() {
|
||||
return 2;
|
||||
}
|
||||
b.inject = [];
|
||||
c = function() { return 4; };
|
||||
return 1 + 2 + c();
|
||||
(function() {
|
||||
return 4;
|
||||
});
|
||||
return 1 + 2 + 4;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "7"
|
||||
}
|
||||
|
||||
defun_label: {
|
||||
@@ -5054,9 +5068,7 @@ defun_var_1: {
|
||||
console.log(typeof a, typeof b);
|
||||
}
|
||||
expect: {
|
||||
var a = 42;
|
||||
function a() {}
|
||||
console.log(typeof a, "function");
|
||||
console.log("number", "function");
|
||||
}
|
||||
expect_stdout: "number function"
|
||||
}
|
||||
@@ -5076,9 +5088,7 @@ defun_var_2: {
|
||||
console.log(typeof a, typeof b);
|
||||
}
|
||||
expect: {
|
||||
function a() {}
|
||||
var a = 42;
|
||||
console.log(typeof a, "function");
|
||||
console.log("number", "function");
|
||||
}
|
||||
expect_stdout: "number function"
|
||||
}
|
||||
@@ -5582,3 +5592,814 @@ issue_2992: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3042_1: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {}
|
||||
var a = [ 1, 2 ].map(function() {
|
||||
return new f();
|
||||
});
|
||||
console.log(a[0].constructor === a[1].constructor);
|
||||
}
|
||||
expect: {
|
||||
function f() {}
|
||||
var a = [ 1, 2 ].map(function() {
|
||||
return new f();
|
||||
});
|
||||
console.log(a[0].constructor === a[1].constructor);
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_3042_2: {
|
||||
options = {
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function Foo() {
|
||||
this.isFoo = function(o) {
|
||||
return o instanceof Foo;
|
||||
};
|
||||
}
|
||||
function FooCollection() {
|
||||
this.foos = [1, 1].map(function() {
|
||||
return new Foo();
|
||||
});
|
||||
}
|
||||
var fooCollection = new FooCollection();
|
||||
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[0]));
|
||||
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[1]));
|
||||
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[0]));
|
||||
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[1]));
|
||||
}
|
||||
expect: {
|
||||
function Foo() {
|
||||
this.isFoo = function(o) {
|
||||
return o instanceof Foo;
|
||||
};
|
||||
}
|
||||
var fooCollection = new function() {
|
||||
this.foos = [1, 1].map(function() {
|
||||
return new Foo();
|
||||
});
|
||||
}();
|
||||
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[0]));
|
||||
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[1]));
|
||||
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[0]));
|
||||
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[1]));
|
||||
}
|
||||
expect_stdout: [
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3068_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
do {
|
||||
continue;
|
||||
var b = "defined";
|
||||
} while (b && b.c);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
do {
|
||||
continue;
|
||||
var b = "defined";
|
||||
} while (b && b.c);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3068_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
do {
|
||||
try {
|
||||
while ("" == typeof a);
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
var b = "defined";
|
||||
} while (b && b.c);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
do {
|
||||
try {
|
||||
while ("" == typeof a);
|
||||
} finally {
|
||||
continue;
|
||||
}
|
||||
var b = "defined";
|
||||
} while (b && b.c);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3110_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
properties: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function foo() {
|
||||
return isDev ? "foo" : "bar";
|
||||
}
|
||||
var isDev = true;
|
||||
var obj = {
|
||||
foo: foo
|
||||
};
|
||||
console.log(foo());
|
||||
console.log(obj.foo());
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log("foo"),
|
||||
console.log("foo");
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"foo",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3110_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 4,
|
||||
properties: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function foo() {
|
||||
return isDev ? "foo" : "bar";
|
||||
}
|
||||
var isDev = true;
|
||||
console.log(foo());
|
||||
var obj = {
|
||||
foo: foo
|
||||
};
|
||||
console.log(obj.foo());
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
console.log("foo"),
|
||||
console.log("foo");
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"foo",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3110_3: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
properties: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function foo() {
|
||||
return isDev ? "foo" : "bar";
|
||||
}
|
||||
console.log(foo());
|
||||
var isDev = true;
|
||||
var obj = {
|
||||
foo: foo
|
||||
};
|
||||
console.log(obj.foo());
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
function foo() {
|
||||
return isDev ? "foo" : "bar";
|
||||
}
|
||||
console.log(foo());
|
||||
var isDev = true;
|
||||
var obj = {
|
||||
foo: foo
|
||||
};
|
||||
console.log(obj.foo());
|
||||
})();
|
||||
}
|
||||
expect_stdout: [
|
||||
"bar",
|
||||
"foo",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3113_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
function f() {
|
||||
while (g());
|
||||
}
|
||||
var a = f();
|
||||
function g() {
|
||||
a && a[c++];
|
||||
}
|
||||
g(a = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
function f() {
|
||||
while (g());
|
||||
}
|
||||
var a = f();
|
||||
function g() {
|
||||
a && a[c++];
|
||||
}
|
||||
g(a = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3113_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
function f() {
|
||||
while (g());
|
||||
}
|
||||
var a = f();
|
||||
function g() {
|
||||
a && a[c++];
|
||||
}
|
||||
a = 1;
|
||||
g();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
function f() {
|
||||
while (g());
|
||||
}
|
||||
var a = f();
|
||||
function g() {
|
||||
a && a[c++];
|
||||
}
|
||||
a = 1;
|
||||
g();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3113_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function() {
|
||||
function f() {
|
||||
while (g());
|
||||
}
|
||||
var a;
|
||||
function g() {
|
||||
a && a[c++];
|
||||
}
|
||||
g(a = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
c++;
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_3113_4: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 0;
|
||||
function f() {
|
||||
b += a;
|
||||
}
|
||||
f(f(), ++a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 0;
|
||||
function f() {
|
||||
b += a;
|
||||
}
|
||||
f(f(), ++a);
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "1 1"
|
||||
}
|
||||
|
||||
issue_3113_5: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
console.log(a);
|
||||
}
|
||||
function g() {
|
||||
f();
|
||||
}
|
||||
while (g());
|
||||
var a = 1;
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
console.log(a);
|
||||
}
|
||||
function g() {
|
||||
f();
|
||||
}
|
||||
while (g());
|
||||
var a = 1;
|
||||
f();
|
||||
}
|
||||
expect_stdout: [
|
||||
"undefined",
|
||||
"1",
|
||||
]
|
||||
}
|
||||
|
||||
conditional_nested_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, b = 0;
|
||||
(function f(c) {
|
||||
function g() {
|
||||
c && (c.a = 0);
|
||||
c && (c.a = 0);
|
||||
c && (c[b++] *= 0);
|
||||
}
|
||||
g(a-- && f(g(c = 42)));
|
||||
})();
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, b = 0;
|
||||
(function f(c) {
|
||||
function g() {
|
||||
c && (c.a = 0);
|
||||
c && (c.a = 0);
|
||||
c && (c[b++] *= 0);
|
||||
}
|
||||
g(a-- && f(g(c = 42)));
|
||||
})();
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
conditional_nested_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
(function(a) {
|
||||
function f() {
|
||||
a && c++;
|
||||
}
|
||||
f(!c && f(), a = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
(function(a) {
|
||||
function f() {
|
||||
a && c++;
|
||||
}
|
||||
f(!c && f(), a = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
conditional_nested_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var n = 2, c = 0;
|
||||
(function f(a) {
|
||||
0 < n-- && g(a = 1);
|
||||
function g() {
|
||||
a && c++;
|
||||
}
|
||||
g();
|
||||
0 < n-- && f();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var n = 2, c = 0;
|
||||
(function f(a) {
|
||||
0 < n-- && g(a = 1);
|
||||
function g() {
|
||||
a && c++;
|
||||
}
|
||||
g();
|
||||
0 < n-- && f();
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_2436: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var c;
|
||||
console.log(((c = {
|
||||
a: 1,
|
||||
b: 2
|
||||
}).a = 3, {
|
||||
x: c.a,
|
||||
y: c.b
|
||||
}));
|
||||
}
|
||||
expect: {
|
||||
var c;
|
||||
console.log(((c = {
|
||||
a: 1,
|
||||
b: 2
|
||||
}).a = 3, {
|
||||
x: c.a,
|
||||
y: c.b
|
||||
}));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2916: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function(b) {
|
||||
(function(d) {
|
||||
d[0] = 1;
|
||||
})(b);
|
||||
+b && (c = "PASS");
|
||||
})([]);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function(b) {
|
||||
b[0] = 1;
|
||||
+b && (c = "PASS");
|
||||
})([]);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3125: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o;
|
||||
console.log((function() {
|
||||
this.p++;
|
||||
}.call(o = {
|
||||
p: 6
|
||||
}), o.p));
|
||||
}
|
||||
expect: {
|
||||
var o;
|
||||
console.log((function() {
|
||||
this.p++;
|
||||
}.call(o = {
|
||||
p: 6
|
||||
}), o.p));
|
||||
}
|
||||
expect_stdout: "7"
|
||||
}
|
||||
|
||||
issue_3140_1: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
this();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
this();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3140_2: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
var self = this;
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
self();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
this();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3140_3: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
var self = this;
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
(function() {
|
||||
return self;
|
||||
})()();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
var self = this;
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
(function() {
|
||||
return self;
|
||||
})()();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3140_4: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
var o = {
|
||||
p: this
|
||||
};
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
o.p();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
function f() {
|
||||
}
|
||||
f.g = function g() {
|
||||
var o = {
|
||||
p: this
|
||||
};
|
||||
function h() {
|
||||
console.log(a ? "PASS" : "FAIL");
|
||||
}
|
||||
a = true;
|
||||
o.p();
|
||||
a = false;
|
||||
h.g = g;
|
||||
return h;
|
||||
};
|
||||
return f;
|
||||
})().g().g();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3140_5: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var n = 1, c = 0;
|
||||
(function(a) {
|
||||
var b = function() {
|
||||
this;
|
||||
n-- && h();
|
||||
}();
|
||||
function h() {
|
||||
b && c++;
|
||||
}
|
||||
h(b = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var n = 1, c = 0;
|
||||
(function(a) {
|
||||
var b = function() {
|
||||
this;
|
||||
n-- && h();
|
||||
}();
|
||||
function h() {
|
||||
b && c++;
|
||||
}
|
||||
h(b = 1);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
37
test/compress/regexp.js
Normal file
37
test/compress/regexp.js
Normal file
@@ -0,0 +1,37 @@
|
||||
regexp_simple: {
|
||||
input: {
|
||||
/rx/ig
|
||||
}
|
||||
expect_exact: "/rx/gi;"
|
||||
}
|
||||
|
||||
regexp_slashes: {
|
||||
input: {
|
||||
/\\\/rx\/\\/ig
|
||||
}
|
||||
expect_exact: "/\\\\\\/rx\\/\\\\/gi;"
|
||||
}
|
||||
|
||||
regexp_1: {
|
||||
input: {
|
||||
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/ig)));
|
||||
}
|
||||
expect: {
|
||||
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
|
||||
}
|
||||
expect_stdout: '["PASS","pass"]'
|
||||
}
|
||||
|
||||
regexp_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(JSON.stringify("COMPASS? Overpass.".match(new RegExp("([Sap]+)", "ig"))));
|
||||
}
|
||||
expect: {
|
||||
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
|
||||
}
|
||||
expect_stdout: '["PASS","pass"]'
|
||||
}
|
||||
@@ -876,3 +876,59 @@ forin: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
call: {
|
||||
options = {
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var a = function() {
|
||||
return this;
|
||||
}();
|
||||
function b() {
|
||||
console.log("foo");
|
||||
}
|
||||
b.c = function() {
|
||||
console.log(this === b ? "bar" : "baz");
|
||||
};
|
||||
(a, b)();
|
||||
(a, b.c)();
|
||||
(a, function() {
|
||||
console.log(this === a);
|
||||
})();
|
||||
new (a, b)();
|
||||
new (a, b.c)();
|
||||
new (a, function() {
|
||||
console.log(this === a);
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
var a = function() {
|
||||
return this;
|
||||
}();
|
||||
function b() {
|
||||
console.log("foo");
|
||||
}
|
||||
b.c = function() {
|
||||
console.log(this === b ? "bar" : "baz");
|
||||
},
|
||||
a, b(),
|
||||
(a, b.c)(),
|
||||
a, function() {
|
||||
console.log(this === a);
|
||||
}(),
|
||||
a, new b(),
|
||||
a, new b.c(),
|
||||
a, new function() {
|
||||
console.log(this === a);
|
||||
}();
|
||||
}
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
"baz",
|
||||
"true",
|
||||
"foo",
|
||||
"baz",
|
||||
"false",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -14,6 +14,13 @@ issue_1929: {
|
||||
function f(s) {
|
||||
return s.split(/[\\/]/);
|
||||
}
|
||||
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
|
||||
}
|
||||
expect_exact: "function f(s){return s.split(/[\\\\/]/)}"
|
||||
expect: {
|
||||
function f(s) {
|
||||
return s.split(/[\\/]/);
|
||||
}
|
||||
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
|
||||
}
|
||||
expect_stdout: '["A","B","C","D","E","F"]'
|
||||
}
|
||||
|
||||
@@ -90,17 +90,11 @@ typeof_defun_1: {
|
||||
"function" == typeof h && h();
|
||||
}
|
||||
expect: {
|
||||
function g() {
|
||||
h = 42;
|
||||
console.log("NOPE");
|
||||
}
|
||||
function h() {
|
||||
console.log("YUP");
|
||||
}
|
||||
g = 42;
|
||||
console.log("YES");
|
||||
"function" == typeof g && g();
|
||||
"function" == typeof h && h();
|
||||
h();
|
||||
}
|
||||
expect_stdout: [
|
||||
"YES",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var fs = require("fs");
|
||||
var parse = require("url").parse;
|
||||
var path = require("path");
|
||||
|
||||
try {
|
||||
@@ -19,7 +20,9 @@ module.exports = function(url, callback) {
|
||||
var result = read(url);
|
||||
result.on("error", function(e) {
|
||||
if (e.code != "ENOENT") return callback(e);
|
||||
require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
|
||||
var options = parse(url);
|
||||
options.rejectUnauthorized = false;
|
||||
require(options.protocol.slice(0, -1)).get(options, function(res) {
|
||||
if (res.statusCode !== 200) return callback(res);
|
||||
res.pipe(fs.createWriteStream(local(url)).on("close", function() {
|
||||
callback(null, read(url));
|
||||
|
||||
4
test/input/enclose/input.js
Normal file
4
test/input/enclose/input.js
Normal file
@@ -0,0 +1,4 @@
|
||||
function enclose() {
|
||||
console.log("test enclose");
|
||||
}
|
||||
enclose();
|
||||
@@ -1,5 +1,5 @@
|
||||
function test(a){
|
||||
"aaaaaaaaaaaaaaaa"
|
||||
;a(err,data),a(err,data)
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQyxJQUFLQyJ9
|
||||
;a(err,data),a(err,
|
||||
data)}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQztBQUFLQyJ9
|
||||
2
test/input/pr-3040/expect.js
Normal file
2
test/input/pr-3040/expect.js
Normal file
@@ -0,0 +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)));
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiYXJyIl0sIm1hcHBpbmdzIjoiMEpBQWNBLEtBQVFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3Qge2Zvb30gPSByZXF1aXJlKFwiYmFyXCIpO1xuY29uc3Qge2hlbGxvfSA9IHJlcXVpcmUoXCJ3b3JsZFwiKTtcblxuZm9vLngoLi4uZm9vLnkoaGVsbG8ueikpO1xuIl19
|
||||
11
test/input/pr-3040/input.js
Normal file
11
test/input/pr-3040/input.js
Normal file
@@ -0,0 +1,11 @@
|
||||
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=input.js.map
|
||||
1
test/input/pr-3040/input.js.map
Normal file
1
test/input/pr-3040/input.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["input2.js"],"names":["require","foo","hello","x","apply","_toConsumableArray","y","z"],"mappings":"kLAAcA,QAAQ,OAAfC,aAAAA,kBACSD,QAAQ,SAAjBE,gBAAAA,MAEPD,IAAIE,EAAJC,MAAAH,IAAAI,mBAASJ,IAAIK,EAAEJ,MAAMK","sourcesContent":["const {foo} = require(\"bar\");\nconst {hello} = require(\"world\");\n\nfoo.x(...foo.y(hello.z));\n"]}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var site = "http://browserbench.org/JetStream";
|
||||
var site = "https://browserbench.org/JetStream";
|
||||
if (typeof phantom == "undefined") {
|
||||
require("../tools/exit");
|
||||
var args = process.argv.slice(2);
|
||||
|
||||
122
test/mocha.js
122
test/mocha.js
@@ -1,24 +1,114 @@
|
||||
var fs = require("fs");
|
||||
var Mocha = require("mocha");
|
||||
var path = require("path");
|
||||
|
||||
// Instantiate a Mocha instance
|
||||
var mocha = new Mocha({
|
||||
timeout: 5000
|
||||
});
|
||||
var testDir = __dirname + "/mocha/";
|
||||
var config = {
|
||||
limit: 5000,
|
||||
timeout: function(limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
};
|
||||
var tasks = [];
|
||||
var titles = [];
|
||||
describe = function(title, fn) {
|
||||
config = Object.create(config);
|
||||
titles.push(title);
|
||||
fn.call(config);
|
||||
titles.pop();
|
||||
config = Object.getPrototypeOf(config);
|
||||
};
|
||||
it = function(title, fn) {
|
||||
fn.limit = config.limit;
|
||||
fn.titles = titles.slice();
|
||||
fn.titles.push(title);
|
||||
tasks.push(fn);
|
||||
};
|
||||
|
||||
// Add each .js file to the Mocha instance
|
||||
fs.readdirSync(testDir).filter(function(file) {
|
||||
fs.readdirSync("test/mocha").filter(function(file) {
|
||||
return /\.js$/.test(file);
|
||||
}).forEach(function(file) {
|
||||
mocha.addFile(path.join(testDir, file));
|
||||
require("./mocha/" + file);
|
||||
});
|
||||
|
||||
module.exports = function() {
|
||||
mocha.run(function(failures) {
|
||||
if (failures) process.on("exit", function() {
|
||||
process.exit(failures);
|
||||
function log_titles(log, current, marker) {
|
||||
var indent = "";
|
||||
var writing = false;
|
||||
for (var i = 0; i < current.length; i++, indent += " ") {
|
||||
if (titles[i] != current[i]) writing = true;
|
||||
if (writing) log(indent + (i == current.length - 1 && marker || "") + current[i]);
|
||||
}
|
||||
titles = current;
|
||||
}
|
||||
|
||||
function red(text) {
|
||||
return "\u001B[31m" + text + "\u001B[39m";
|
||||
}
|
||||
|
||||
function green(text) {
|
||||
return "\u001B[32m" + text + "\u001B[39m";
|
||||
}
|
||||
|
||||
var errors = [];
|
||||
var total = tasks.length;
|
||||
titles = [];
|
||||
process.nextTick(function run() {
|
||||
var task = tasks.shift();
|
||||
if (task) try {
|
||||
var elapsed = Date.now();
|
||||
var timer;
|
||||
var done = function() {
|
||||
reset();
|
||||
elapsed = Date.now() - elapsed;
|
||||
if (elapsed > task.limit) {
|
||||
throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms");
|
||||
}
|
||||
log_titles(console.log, task.titles, green('\u221A '));
|
||||
process.nextTick(run);
|
||||
};
|
||||
if (task.length) {
|
||||
task.timeout = function(limit) {
|
||||
clearTimeout(timer);
|
||||
task.limit = limit;
|
||||
timer = setTimeout(function() {
|
||||
raise(new Error("Timed out: exceeds " + limit + "ms"));
|
||||
}, limit);
|
||||
};
|
||||
task.timeout(task.limit);
|
||||
process.on("uncaughtException", raise);
|
||||
task.call(task, done);
|
||||
} else {
|
||||
task.timeout = config.timeout;
|
||||
task.call(task);
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
raise(err);
|
||||
} else if (errors.length) {
|
||||
console.error();
|
||||
console.log(red(errors.length + " test(s) failed!"));
|
||||
titles = [];
|
||||
errors.forEach(function(titles, index) {
|
||||
console.error();
|
||||
log_titles(console.error, titles, (index + 1) + ") ");
|
||||
var lines = titles.error.stack.split('\n');
|
||||
console.error(red(lines[0]));
|
||||
console.error(lines.slice(1).join("\n"));
|
||||
});
|
||||
});
|
||||
};
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log();
|
||||
console.log(green(total + " test(s) passed."));
|
||||
}
|
||||
|
||||
function raise(err) {
|
||||
reset();
|
||||
task.titles.error = err;
|
||||
errors.push(task.titles);
|
||||
log_titles(console.log, task.titles, red('\u00D7 '));
|
||||
process.nextTick(run);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
clearTimeout(timer);
|
||||
done = function() {};
|
||||
process.removeListener("uncaughtException", raise);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
var assert = require("assert");
|
||||
var exec = require("child_process").exec;
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var fs = require("fs");
|
||||
|
||||
function read(path) {
|
||||
return readFileSync(path, "utf8");
|
||||
return fs.readFileSync(path, "utf8");
|
||||
}
|
||||
|
||||
describe("bin/uglifyjs", function () {
|
||||
describe("bin/uglifyjs", function() {
|
||||
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||
it("should produce a functional build when using --self", function (done) {
|
||||
this.timeout(30000);
|
||||
@@ -56,6 +56,18 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should give sensible error against invalid input source map", function(done) {
|
||||
var command = uglifyjscmd + " test/mocha.js --source-map content=blah,url=inline";
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.deepEqual(stderr.split(/\n/).slice(0, 2), [
|
||||
"INFO: Using input source map: blah",
|
||||
"ERROR: invalid input source map: blah",
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should append source map to output when using --source-map url=inline", function (done) {
|
||||
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map url=inline";
|
||||
|
||||
@@ -88,12 +100,42 @@ describe("bin/uglifyjs", function () {
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
|
||||
var stderrLines = stderr.split('\n');
|
||||
assert.strictEqual(stderrLines[0], 'INFO: Using input source map: test/input/issue-2082/sample.js.map');
|
||||
var stderrLines = stderr.split("\n");
|
||||
assert.strictEqual(stderrLines[0], "INFO: Using input source map: test/input/issue-2082/sample.js.map");
|
||||
assert.notStrictEqual(stderrLines[1], 'INFO: Using input source map: {"version": 3,"sources": ["index.js"],"mappings": ";"}');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should not load source map before finish reading from STDIN", function(done) {
|
||||
var mapFile = "tmp/input.js.map";
|
||||
try {
|
||||
fs.mkdirSync("./tmp");
|
||||
} catch (e) {
|
||||
if (e.code != "EEXIST") throw e;
|
||||
}
|
||||
try {
|
||||
fs.unlinkSync(mapFile);
|
||||
} catch (e) {
|
||||
if (e.code != "ENOENT") throw e;
|
||||
}
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
"--source-map", "content=" + mapFile,
|
||||
"--source-map", "includeSources=true",
|
||||
"--source-map", "url=inline",
|
||||
].join(" ");
|
||||
|
||||
var child = exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(stdout, read("test/input/pr-3040/expect.js"));
|
||||
done();
|
||||
});
|
||||
setTimeout(function() {
|
||||
fs.writeFileSync(mapFile, read("test/input/pr-3040/input.js.map"));
|
||||
child.stdin.end(read("test/input/pr-3040/input.js"));
|
||||
}, 1000);
|
||||
});
|
||||
it("Should work with --keep-fnames (mangle only)", function (done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
|
||||
|
||||
@@ -175,7 +217,14 @@ describe("bin/uglifyjs", function () {
|
||||
});
|
||||
});
|
||||
it("Should process inline source map", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-520/input.js -mc toplevel --source-map content=inline,url=inline";
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
"test/input/issue-520/input.js",
|
||||
"-mc", "toplevel",
|
||||
"--source-map", "content=inline",
|
||||
"--source-map", "includeSources=true",
|
||||
"--source-map", "url=inline",
|
||||
].join(" ");
|
||||
|
||||
exec(command, function (err, stdout) {
|
||||
if (err) throw err;
|
||||
@@ -195,16 +244,29 @@ describe("bin/uglifyjs", function () {
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
|
||||
"",
|
||||
].join("\n"));
|
||||
assert.strictEqual(stderr, "WARN: inline source map not found\n");
|
||||
var stderrLines = stderr.split("\n");
|
||||
assert.strictEqual(stderrLines[0], "WARN: inline source map not found: test/input/issue-1323/sample.js");
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should fail with multiple input and inline source map", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-520/input.js test/input/issue-520/output.js --source-map content=inline,url=inline";
|
||||
it("Should handle multiple input and inline source map", function(done) {
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
"test/input/issue-520/input.js",
|
||||
"test/input/issue-1323/sample.js",
|
||||
"--source-map", "content=inline,url=inline",
|
||||
].join(" ");
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stderr.split(/\n/)[0], "ERROR: inline source map only works with singular input");
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(stdout, [
|
||||
"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==",
|
||||
"",
|
||||
].join("\n"));
|
||||
var stderrLines = stderr.split("\n");
|
||||
assert.strictEqual(stderrLines[0], "WARN: inline source map not found: test/input/issue-1323/sample.js");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -682,4 +744,36 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --enclose", function(done) {
|
||||
var command = uglifyjscmd + " test/input/enclose/input.js --enclose";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, '(function(){function enclose(){console.log("test enclose")}enclose()})();\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --enclose arg", function(done) {
|
||||
var command = uglifyjscmd + " test/input/enclose/input.js --enclose undefined";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --enclose arg:value", function(done) {
|
||||
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --enclose & --wrap", function(done) {
|
||||
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window --wrap exports";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,66 +1,68 @@
|
||||
var Uglify = require('../../');
|
||||
var assert = require("assert");
|
||||
var Uglify = require("../../");
|
||||
var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
||||
|
||||
function getMap() {
|
||||
return {
|
||||
"version": 3,
|
||||
"sources": ["index.js"],
|
||||
"names": [],
|
||||
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
|
||||
"file": "bundle.js",
|
||||
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
|
||||
};
|
||||
}
|
||||
|
||||
function prepareMap(sourceMap) {
|
||||
var code = [
|
||||
'"use strict";',
|
||||
"",
|
||||
"var foo = function foo(x) {",
|
||||
' return "foo " + x;',
|
||||
"};",
|
||||
'console.log(foo("bar"));',
|
||||
"",
|
||||
"//# sourceMappingURL=bundle.js.map",
|
||||
].join("\n");
|
||||
var result = Uglify.minify(code, {
|
||||
sourceMap: {
|
||||
content: sourceMap,
|
||||
includeSources: true,
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
return new SourceMapConsumer(result.map);
|
||||
}
|
||||
|
||||
describe("input sourcemaps", function() {
|
||||
var transpilemap, map;
|
||||
|
||||
function getMap() {
|
||||
return {
|
||||
"version": 3,
|
||||
"sources": ["index.js"],
|
||||
"names": [],
|
||||
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
|
||||
"file": "bundle.js",
|
||||
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
|
||||
};
|
||||
}
|
||||
|
||||
function prepareMap(sourceMap) {
|
||||
var transpiled = '"use strict";\n\n' +
|
||||
'var foo = function foo(x) {\n return "foo " + x;\n};\n' +
|
||||
'console.log(foo("bar"));\n\n' +
|
||||
'//# sourceMappingURL=bundle.js.map';
|
||||
|
||||
transpilemap = sourceMap || getMap();
|
||||
|
||||
var result = Uglify.minify(transpiled, {
|
||||
sourceMap: {
|
||||
content: transpilemap
|
||||
}
|
||||
});
|
||||
|
||||
map = new SourceMapConsumer(result.map);
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
prepareMap();
|
||||
});
|
||||
|
||||
it("Should copy over original sourcesContent", function() {
|
||||
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
|
||||
var orig = getMap();
|
||||
var map = prepareMap(orig);
|
||||
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]);
|
||||
});
|
||||
|
||||
it("Should copy sourcesContent if sources are relative", function () {
|
||||
it("Should copy sourcesContent if sources are relative", function() {
|
||||
var relativeMap = getMap();
|
||||
relativeMap.sources = ['./index.js'];
|
||||
|
||||
prepareMap(relativeMap);
|
||||
var map = prepareMap(relativeMap);
|
||||
assert.notEqual(map.sourcesContent, null);
|
||||
assert.equal(map.sourcesContent.length, 1);
|
||||
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
|
||||
assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]);
|
||||
});
|
||||
|
||||
it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882)", function() {
|
||||
it("Should not have invalid mappings from inputSourceMap (issue #882)", function() {
|
||||
var map = prepareMap(getMap());
|
||||
// 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";
|
||||
map.eachMapping(function(mapping) {
|
||||
assert.ok(mapping.originalLine <= 2, msg)
|
||||
assert.ok(mapping.originalLine <= 2, msg);
|
||||
});
|
||||
|
||||
map.allGeneratedPositionsFor({source: "index.js", line: 1, column: 1}).forEach(function(pos) {
|
||||
map.allGeneratedPositionsFor({
|
||||
source: "index.js",
|
||||
line: 1,
|
||||
column: 1
|
||||
}).forEach(function(pos) {
|
||||
assert.ok(pos.line <= 2, msg);
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,99 +186,6 @@ describe("minify", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("inSourceMap", function() {
|
||||
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
|
||||
var result = Uglify.minify(read("./test/input/issue-1236/simple.js"), {
|
||||
sourceMap: {
|
||||
content: read("./test/input/issue-1236/simple.js.map"),
|
||||
filename: "simple.min.js",
|
||||
includeSources: true
|
||||
}
|
||||
});
|
||||
|
||||
var map = JSON.parse(result.map);
|
||||
|
||||
assert.equal(map.file, 'simple.min.js');
|
||||
assert.equal(map.sourcesContent.length, 1);
|
||||
assert.equal(map.sourcesContent[0],
|
||||
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
||||
});
|
||||
it("Should process inline source map", function() {
|
||||
var code = Uglify.minify(read("./test/input/issue-520/input.js"), {
|
||||
compress: { toplevel: true },
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
url: "inline"
|
||||
}
|
||||
}).code + "\n";
|
||||
assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8"));
|
||||
});
|
||||
it("Should warn for missing inline source map", function() {
|
||||
var warn_function = Uglify.AST_Node.warn_function;
|
||||
var warnings = [];
|
||||
Uglify.AST_Node.warn_function = function(txt) {
|
||||
warnings.push(txt);
|
||||
};
|
||||
try {
|
||||
var result = Uglify.minify(read("./test/input/issue-1323/sample.js"), {
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: "inline"
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.code, "var bar=function(bar){return bar};");
|
||||
assert.strictEqual(warnings.length, 1);
|
||||
assert.strictEqual(warnings[0], "inline source map not found");
|
||||
} finally {
|
||||
Uglify.AST_Node.warn_function = warn_function;
|
||||
}
|
||||
});
|
||||
it("Should fail with multiple input and inline source map", function() {
|
||||
var result = Uglify.minify([
|
||||
read("./test/input/issue-520/input.js"),
|
||||
read("./test/input/issue-520/output.js")
|
||||
], {
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
url: "inline"
|
||||
}
|
||||
});
|
||||
var err = result.error;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "Error: inline source map only works with singular input");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sourceMapInline", function() {
|
||||
it("should append source map to output js when sourceMapInline is enabled", function() {
|
||||
var result = Uglify.minify('var a = function(foo) { return foo; };', {
|
||||
sourceMap: {
|
||||
url: "inline"
|
||||
}
|
||||
});
|
||||
var code = result.code;
|
||||
assert.strictEqual(code, "var a=function(n){return n};\n" +
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
|
||||
});
|
||||
it("should not append source map to output js when sourceMapInline is not enabled", function() {
|
||||
var result = Uglify.minify('var a = function(foo) { return foo; };');
|
||||
var code = result.code;
|
||||
assert.strictEqual(code, "var a=function(n){return n};");
|
||||
});
|
||||
it("should work with max_line_len", function() {
|
||||
var result = Uglify.minify(read("./test/input/issue-505/input.js"), {
|
||||
output: {
|
||||
max_line_len: 20
|
||||
},
|
||||
sourceMap: {
|
||||
url: "inline"
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.error, undefined);
|
||||
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#__PURE__", function() {
|
||||
it("should drop #__PURE__ hint after use", function() {
|
||||
var result = Uglify.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', {
|
||||
@@ -312,6 +219,15 @@ describe("minify", function() {
|
||||
assert.strictEqual(err.line, 1);
|
||||
assert.strictEqual(err.col, 12);
|
||||
});
|
||||
it("should reject duplicated label name", function() {
|
||||
var result = Uglify.minify("L:{L:{}}");
|
||||
var err = result.error;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Label L defined twice");
|
||||
assert.strictEqual(err.filename, "0");
|
||||
assert.strictEqual(err.line, 1);
|
||||
assert.strictEqual(err.col, 4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("global_defs", function() {
|
||||
@@ -387,4 +303,45 @@ describe("minify", function() {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("enclose", function() {
|
||||
var code = read("test/input/enclose/input.js");
|
||||
it("Should work with true", function() {
|
||||
var result = Uglify.minify(code, {
|
||||
compress: false,
|
||||
enclose: true,
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '(function(){function enclose(){console.log("test enclose")}enclose()})();');
|
||||
});
|
||||
it("Should work with arg", function() {
|
||||
var result = Uglify.minify(code, {
|
||||
compress: false,
|
||||
enclose: 'undefined',
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();');
|
||||
});
|
||||
it("Should work with arg:value", function() {
|
||||
var result = Uglify.minify(code, {
|
||||
compress: false,
|
||||
enclose: 'window,undefined:window',
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);');
|
||||
});
|
||||
it("Should work alongside wrap", function() {
|
||||
var result = Uglify.minify(code, {
|
||||
compress: false,
|
||||
enclose: 'window,undefined:window',
|
||||
mangle: false,
|
||||
wrap: 'exports',
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
var assert = require("assert");
|
||||
var uglify = require("../../");
|
||||
|
||||
describe("New", function() {
|
||||
describe("parentheses", function() {
|
||||
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
|
||||
var tests = [
|
||||
"new x(1);",
|
||||
@@ -83,4 +83,23 @@ describe("New", function() {
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("Should compress leading parenthesis with reasonable performance", function() {
|
||||
this.timeout(30000);
|
||||
var code = [
|
||||
"({}?0:1)&&x();",
|
||||
"(function(){}).name;",
|
||||
];
|
||||
for (var i = 16; --i >= 0;) {
|
||||
code = code.concat(code);
|
||||
}
|
||||
code = code.join("");
|
||||
var result = uglify.minify(code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
// Dismal performance for `assert.strictEqual()` in Node.js 6
|
||||
assert.ok(result.code === code);
|
||||
});
|
||||
});
|
||||
212
test/mocha/sourcemaps.js
Normal file
212
test/mocha/sourcemaps.js
Normal file
@@ -0,0 +1,212 @@
|
||||
var assert = require("assert");
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var Uglify = require("../../");
|
||||
|
||||
function read(path) {
|
||||
return readFileSync(path, "utf8");
|
||||
}
|
||||
|
||||
function source_map(code) {
|
||||
return JSON.parse(Uglify.minify(code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: true,
|
||||
}).map);
|
||||
}
|
||||
|
||||
describe("sourcemaps", function() {
|
||||
it("Should give correct version", function() {
|
||||
var map = source_map("var x = 1 + 1;");
|
||||
assert.strictEqual(map.version, 3);
|
||||
assert.deepEqual(map.names, [ "x" ]);
|
||||
});
|
||||
|
||||
it("Should give correct names", function() {
|
||||
var map = source_map([
|
||||
"({",
|
||||
" get enabled() {",
|
||||
" return 3;",
|
||||
" },",
|
||||
" set enabled(x) {",
|
||||
" ;",
|
||||
" }",
|
||||
"});",
|
||||
].join("\n"));
|
||||
assert.deepEqual(map.names, [ "enabled", "x" ]);
|
||||
});
|
||||
|
||||
it("Should mark array/object literals", function() {
|
||||
var result = Uglify.minify([
|
||||
"var obj = {};",
|
||||
"obj.wat([]);",
|
||||
].join("\n"), {
|
||||
sourceMap: true,
|
||||
toplevel: true,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, "({}).wat([]);");
|
||||
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["wat"],"mappings":"CAAU,IACNA,IAAI"}');
|
||||
});
|
||||
|
||||
describe("inSourceMap", function() {
|
||||
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
|
||||
var result = Uglify.minify(read("./test/input/issue-1236/simple.js"), {
|
||||
sourceMap: {
|
||||
content: read("./test/input/issue-1236/simple.js.map"),
|
||||
filename: "simple.min.js",
|
||||
includeSources: true
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var map = JSON.parse(result.map);
|
||||
assert.equal(map.file, "simple.min.js");
|
||||
assert.equal(map.sourcesContent.length, 1);
|
||||
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
||||
});
|
||||
it("Should process inline source map", function() {
|
||||
var result = Uglify.minify(read("./test/input/issue-520/input.js"), {
|
||||
compress: { toplevel: true },
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
includeSources: true,
|
||||
url: "inline"
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8"));
|
||||
});
|
||||
it("Should warn for missing inline source map", function() {
|
||||
var warn_function = Uglify.AST_Node.warn_function;
|
||||
var warnings = [];
|
||||
Uglify.AST_Node.warn_function = function(txt) {
|
||||
warnings.push(txt);
|
||||
};
|
||||
try {
|
||||
var result = Uglify.minify(read("./test/input/issue-1323/sample.js"), {
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: "inline"
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.code, "var bar=function(bar){return bar};");
|
||||
assert.strictEqual(warnings.length, 1);
|
||||
assert.strictEqual(warnings[0], "inline source map not found: 0");
|
||||
} finally {
|
||||
Uglify.AST_Node.warn_function = warn_function;
|
||||
}
|
||||
});
|
||||
it("Should handle multiple input and inline source map", function() {
|
||||
var warn_function = Uglify.AST_Node.warn_function;
|
||||
var warnings = [];
|
||||
Uglify.AST_Node.warn_function = function(txt) {
|
||||
warnings.push(txt);
|
||||
};
|
||||
try {
|
||||
var result = Uglify.minify([
|
||||
read("./test/input/issue-520/input.js"),
|
||||
read("./test/input/issue-1323/sample.js"),
|
||||
], {
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
url: "inline",
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, [
|
||||
"var Foo=function(){console.log(3)};new Foo;var bar=function(o){return o};",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLElBQVMsSUFBSUYsSUNBbkQsSUFBSUcsSUFDQSxTQUFjQSxHQUNWLE9BQU9BIn0=",
|
||||
].join("\n"));
|
||||
assert.strictEqual(warnings.length, 1);
|
||||
assert.strictEqual(warnings[0], "inline source map not found: 1");
|
||||
} finally {
|
||||
Uglify.AST_Node.warn_function = warn_function;
|
||||
}
|
||||
});
|
||||
it("Should drop source contents for includeSources=false", function() {
|
||||
var result = Uglify.minify(read("./test/input/issue-520/input.js"), {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
includeSources: true,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var map = JSON.parse(result.map);
|
||||
assert.strictEqual(map.sourcesContent.length, 1);
|
||||
result = Uglify.minify(result.code, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: result.map,
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
map = JSON.parse(result.map);
|
||||
assert.ok(!("sourcesContent" in map));
|
||||
});
|
||||
});
|
||||
|
||||
describe("sourceMapInline", function() {
|
||||
it("Should append source map to output js when sourceMapInline is enabled", function() {
|
||||
var result = Uglify.minify('var a = function(foo) { return foo; };', {
|
||||
sourceMap: {
|
||||
url: "inline"
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var code = result.code;
|
||||
assert.strictEqual(code, "var a=function(n){return n};\n" +
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
|
||||
});
|
||||
it("Should not append source map to output js when sourceMapInline is not enabled", function() {
|
||||
var result = Uglify.minify('var a = function(foo) { return foo; };');
|
||||
if (result.error) throw result.error;
|
||||
var code = result.code;
|
||||
assert.strictEqual(code, "var a=function(n){return n};");
|
||||
});
|
||||
it("Should work with max_line_len", function() {
|
||||
var result = Uglify.minify(read("./test/input/issue-505/input.js"), {
|
||||
output: {
|
||||
max_line_len: 20
|
||||
},
|
||||
sourceMap: {
|
||||
url: "inline"
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
|
||||
});
|
||||
it("Should work with unicode characters", function() {
|
||||
var code = [
|
||||
"var tëst = '→unicøde←';",
|
||||
"alert(tëst);",
|
||||
].join("\n");
|
||||
var result = Uglify.minify(code, {
|
||||
sourceMap: {
|
||||
includeSources: true,
|
||||
url: "inline",
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
var map = JSON.parse(result.map);
|
||||
assert.strictEqual(map.sourcesContent.length, 1);
|
||||
assert.strictEqual(map.sourcesContent[0], code);
|
||||
var encoded = result.code.slice(result.code.lastIndexOf(",") + 1);
|
||||
map = JSON.parse(new Buffer(encoded, "base64").toString());
|
||||
assert.strictEqual(map.sourcesContent.length, 1);
|
||||
assert.strictEqual(map.sourcesContent[0], code);
|
||||
result = Uglify.minify(result.code, {
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
includeSources: true,
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
map = JSON.parse(result.map);
|
||||
assert.strictEqual(map.names.length, 2);
|
||||
assert.strictEqual(map.names[0], "tëst");
|
||||
assert.strictEqual(map.names[1], "alert");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -23,6 +23,15 @@ describe("spidermonkey export/import sanity test", function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("should not add unnecessary escape slashes to regexps", function() {
|
||||
var input = "/[\\\\/]/;";
|
||||
var ast = uglify.parse(input).to_mozilla_ast();
|
||||
assert.equal(
|
||||
uglify.AST_Node.from_mozilla_ast(ast).print_to_string(),
|
||||
input
|
||||
);
|
||||
});
|
||||
|
||||
it("Should judge between directives and strings correctly on import", function() {
|
||||
var tests = [
|
||||
{
|
||||
|
||||
@@ -18,12 +18,8 @@ if (failures) {
|
||||
console.error("!!! " + Object.keys(failed_files).join(", "));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var mocha_tests = require("./mocha.js");
|
||||
mocha_tests();
|
||||
|
||||
var run_sourcemaps_tests = require('./sourcemaps');
|
||||
run_sourcemaps_tests();
|
||||
console.log();
|
||||
require("./mocha.js");
|
||||
|
||||
/* -----[ utils ]----- */
|
||||
|
||||
@@ -49,16 +45,9 @@ function log_test(name) {
|
||||
}
|
||||
|
||||
function find_test_files(dir) {
|
||||
var files = fs.readdirSync(dir).filter(function(name){
|
||||
return fs.readdirSync(dir).filter(function(name) {
|
||||
return /\.js$/i.test(name);
|
||||
});
|
||||
if (process.argv.length > 2) {
|
||||
var x = process.argv.slice(2);
|
||||
files = files.filter(function(f){
|
||||
return x.indexOf(f) >= 0;
|
||||
});
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function test_directory(dir) {
|
||||
@@ -182,7 +171,7 @@ function run_compress_tests() {
|
||||
}
|
||||
if (test.expect_stdout
|
||||
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
||||
var stdout = sandbox.run_code(input_code, true);
|
||||
var stdout = run_code(input_code);
|
||||
if (test.expect_stdout === true) {
|
||||
test.expect_stdout = stdout;
|
||||
}
|
||||
@@ -196,7 +185,7 @@ function run_compress_tests() {
|
||||
});
|
||||
return false;
|
||||
}
|
||||
stdout = sandbox.run_code(output, true);
|
||||
stdout = run_code(output);
|
||||
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_formatted,
|
||||
@@ -354,6 +343,11 @@ function evaluate(code) {
|
||||
return new Function("return(" + code + ")")();
|
||||
}
|
||||
|
||||
function run_code(code) {
|
||||
var result = sandbox.run_code(code, true);
|
||||
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
|
||||
}
|
||||
|
||||
// Try to reminify original input with standard options
|
||||
// to see if it matches expect_stdout.
|
||||
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
||||
@@ -377,7 +371,7 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
var stdout = sandbox.run_code(result.code, true);
|
||||
var stdout = run_code(result.code);
|
||||
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
|
||||
stdout = expect_stdout;
|
||||
}
|
||||
|
||||
@@ -2,24 +2,18 @@ var semver = require("semver");
|
||||
var vm = require("vm");
|
||||
|
||||
function createContext() {
|
||||
var context = Object.create(null);
|
||||
Object.defineProperty(context, "console", {
|
||||
value: function() {
|
||||
var con = Object.create(null);
|
||||
Object.defineProperty(con, "log", {
|
||||
value: function(msg) {
|
||||
if (arguments.length == 1 && typeof msg == "string") {
|
||||
return console.log("%s", msg);
|
||||
}
|
||||
return console.log.apply(console, [].map.call(arguments, function(arg) {
|
||||
return safe_log(arg, 3);
|
||||
}));
|
||||
return vm.createContext(Object.defineProperty({}, "console", {
|
||||
value: {
|
||||
log: function(msg) {
|
||||
if (arguments.length == 1 && typeof msg == "string") {
|
||||
return console.log("%s", msg);
|
||||
}
|
||||
});
|
||||
return con;
|
||||
}()
|
||||
});
|
||||
return vm.createContext(context);
|
||||
return console.log.apply(console, [].map.call(arguments, function(arg) {
|
||||
return safe_log(arg, 3);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function safe_log(arg, level) {
|
||||
@@ -40,7 +34,7 @@ function safe_log(arg, level) {
|
||||
}
|
||||
|
||||
function strip_func_ids(text) {
|
||||
return text.toString().replace(/F[0-9]{6}N/g, "<F<>N>");
|
||||
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
|
||||
}
|
||||
|
||||
var context;
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
var UglifyJS = require("..");
|
||||
var ok = require("assert");
|
||||
|
||||
module.exports = function () {
|
||||
console.log("--- Sourcemaps tests");
|
||||
|
||||
var basic = source_map([
|
||||
'var x = 1 + 1;'
|
||||
].join('\n'));
|
||||
|
||||
ok.equal(basic.version, 3);
|
||||
ok.deepEqual(basic.names, ['x']);
|
||||
|
||||
var issue836 = source_map([
|
||||
"({",
|
||||
" get enabled() {",
|
||||
" return 3;",
|
||||
" },",
|
||||
" set enabled(x) {",
|
||||
" ;",
|
||||
" }",
|
||||
"});",
|
||||
].join("\n"));
|
||||
|
||||
ok.deepEqual(issue836.names, ['enabled', 'x']);
|
||||
}
|
||||
|
||||
function source_map(js) {
|
||||
return JSON.parse(UglifyJS.minify(js, {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: true
|
||||
}).map);
|
||||
}
|
||||
|
||||
// Run standalone
|
||||
if (module.parent === null) {
|
||||
module.exports();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,13 @@
|
||||
{
|
||||
"toplevel": true
|
||||
},
|
||||
{
|
||||
"compress": {
|
||||
"passes": 1e6,
|
||||
"unsafe": true
|
||||
},
|
||||
"toplevel": true
|
||||
},
|
||||
{
|
||||
"compress": {
|
||||
"keep_fargs": false,
|
||||
|
||||
Reference in New Issue
Block a user