Merge branch 'master' into harmony
This commit is contained in:
31
README.md
31
README.md
@@ -285,6 +285,21 @@ of mangled property names.
|
|||||||
Using the name cache is not necessary if you compress all your files in a
|
Using the name cache is not necessary if you compress all your files in a
|
||||||
single call to UglifyJS.
|
single call to UglifyJS.
|
||||||
|
|
||||||
|
#### Debugging property name mangling
|
||||||
|
|
||||||
|
You can also pass `--mangle-props-debug` in order to mangle property names
|
||||||
|
without completely obscuring them. For example the property `o.foo`
|
||||||
|
would mangle to `o._$foo$_` with this option. This allows property mangling
|
||||||
|
of a large codebase while still being able to debug the code and identify
|
||||||
|
where mangling is breaking things.
|
||||||
|
|
||||||
|
You can also pass a custom suffix using `--mangle-props-debug=XYZ`. This would then
|
||||||
|
mangle `o.foo` to `o._$foo$XYZ_`. You can change this each time you compile a
|
||||||
|
script to identify how a property got mangled. One technique is to pass a
|
||||||
|
random number on every compile to simulate mangling changing with different
|
||||||
|
inputs (e.g. as you update the input script with new properties), and to help
|
||||||
|
identify mistakes like writing mangled keys to storage.
|
||||||
|
|
||||||
## Compressor options
|
## Compressor options
|
||||||
|
|
||||||
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
||||||
@@ -639,15 +654,22 @@ To generate a source map with the fromString option, you can also use an object:
|
|||||||
```javascript
|
```javascript
|
||||||
var result = UglifyJS.minify({"file1.js": "var a = function () {};"}, {
|
var result = UglifyJS.minify({"file1.js": "var a = function () {};"}, {
|
||||||
outSourceMap: "out.js.map",
|
outSourceMap: "out.js.map",
|
||||||
|
outFileName: "out.js",
|
||||||
fromString: true
|
fromString: true
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that the source map is not saved in a file, it's just returned in
|
Note that the source map is not saved in a file, it's just returned in
|
||||||
`result.map`. The value passed for `outSourceMap` is only used to set the
|
`result.map`. The value passed for `outSourceMap` is only used to set
|
||||||
`file` attribute in the source map (see [the spec][sm-spec]). You can set
|
`//# sourceMappingURL=out.js.map` in `result.code`. The value of
|
||||||
option `sourceMapInline` to be `true` and source map will be appended to
|
`outFileName` is only used to set `file` attribute in source map file.
|
||||||
code.
|
|
||||||
|
The `file` attribute in the source map (see [the spec][sm-spec]) will
|
||||||
|
use `outFileName` firstly, if it's falsy, then will be deduced from
|
||||||
|
`outSourceMap` (by removing `'.map'`).
|
||||||
|
|
||||||
|
You can set option `sourceMapInline` to be `true` and source map will
|
||||||
|
be appended to code.
|
||||||
|
|
||||||
You can also specify sourceRoot property to be included in source map:
|
You can also specify sourceRoot property to be included in source map:
|
||||||
```javascript
|
```javascript
|
||||||
@@ -752,6 +774,7 @@ Other options:
|
|||||||
|
|
||||||
- `regex` — Pass a RegExp to only mangle certain names (maps to the `--mangle-regex` CLI arguments option)
|
- `regex` — Pass a RegExp to only mangle certain names (maps to the `--mangle-regex` CLI arguments option)
|
||||||
- `ignore_quoted` – Only mangle unquoted property names (maps to the `--mangle-props 2` CLI arguments option)
|
- `ignore_quoted` – Only mangle unquoted property names (maps to the `--mangle-props 2` CLI arguments option)
|
||||||
|
- `debug` – Mangle names with the original name still present (maps to the `--mangle-props-debug` CLI arguments option). Defaults to `false`. Pass an empty string to enable, or a non-empty string to set the suffix.
|
||||||
|
|
||||||
We could add more options to `UglifyJS.minify` — if you need additional
|
We could add more options to `UglifyJS.minify` — if you need additional
|
||||||
functionality please suggest!
|
functionality please suggest!
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.string("beautify")
|
.string("beautify")
|
||||||
.string("m")
|
.string("m")
|
||||||
.string("mangle")
|
.string("mangle")
|
||||||
|
.string("mangle-props-debug")
|
||||||
.string("c")
|
.string("c")
|
||||||
.string("compress")
|
.string("compress")
|
||||||
.string("d")
|
.string("d")
|
||||||
@@ -419,7 +420,8 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
cache : cache,
|
cache : cache,
|
||||||
only_cache : !ARGS.mangle_props,
|
only_cache : !ARGS.mangle_props,
|
||||||
regex : regex,
|
regex : regex,
|
||||||
ignore_quoted : ARGS.mangle_props == 2
|
ignore_quoted : ARGS.mangle_props == 2,
|
||||||
|
debug : typeof ARGS.mangle_props_debug === "undefined" ? false : ARGS.mangle_props_debug
|
||||||
});
|
});
|
||||||
writeNameCache("props", cache);
|
writeNameCache("props", cache);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -932,7 +932,7 @@ merge(Compressor.prototype, {
|
|||||||
(function (def){
|
(function (def){
|
||||||
var unary_bool = [ "!", "delete" ];
|
var unary_bool = [ "!", "delete" ];
|
||||||
var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
|
var binary_bool = [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ];
|
||||||
def(AST_Node, function(){ return false });
|
def(AST_Node, return_false);
|
||||||
def(AST_UnaryPrefix, function(){
|
def(AST_UnaryPrefix, function(){
|
||||||
return member(this.operator, unary_bool);
|
return member(this.operator, unary_bool);
|
||||||
});
|
});
|
||||||
@@ -950,8 +950,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Seq, function(){
|
def(AST_Seq, function(){
|
||||||
return this.cdr.is_boolean();
|
return this.cdr.is_boolean();
|
||||||
});
|
});
|
||||||
def(AST_True, function(){ return true });
|
def(AST_True, return_true);
|
||||||
def(AST_False, function(){ return true });
|
def(AST_False, return_true);
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
node.DEFMETHOD("is_boolean", func);
|
node.DEFMETHOD("is_boolean", func);
|
||||||
});
|
});
|
||||||
@@ -1228,11 +1228,11 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
// determine if expression has side effects
|
// determine if expression has side effects
|
||||||
(function(def){
|
(function(def){
|
||||||
def(AST_Node, function(compressor){ return true });
|
def(AST_Node, return_true);
|
||||||
|
|
||||||
def(AST_EmptyStatement, function(compressor){ return false });
|
def(AST_EmptyStatement, return_false);
|
||||||
def(AST_Constant, function(compressor){ return false });
|
def(AST_Constant, return_false);
|
||||||
def(AST_This, function(compressor){ return false });
|
def(AST_This, return_false);
|
||||||
|
|
||||||
def(AST_Call, function(compressor){
|
def(AST_Call, function(compressor){
|
||||||
var pure = compressor.option("pure_funcs");
|
var pure = compressor.option("pure_funcs");
|
||||||
@@ -1252,15 +1252,15 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_SimpleStatement, function(compressor){
|
def(AST_SimpleStatement, function(compressor){
|
||||||
return this.body.has_side_effects(compressor);
|
return this.body.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Defun, function(compressor){ return true });
|
def(AST_Defun, return_true);
|
||||||
def(AST_Function, function(compressor){ return false });
|
def(AST_Function, return_false);
|
||||||
def(AST_Class, function(compressor){ return false });
|
def(AST_Class, return_false);
|
||||||
def(AST_DefClass, function(compressor){ return true });
|
def(AST_DefClass, return_true);
|
||||||
def(AST_Binary, function(compressor){
|
def(AST_Binary, function(compressor){
|
||||||
return this.left.has_side_effects(compressor)
|
return this.left.has_side_effects(compressor)
|
||||||
|| this.right.has_side_effects(compressor);
|
|| this.right.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Assign, function(compressor){ return true });
|
def(AST_Assign, return_true);
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
return this.condition.has_side_effects(compressor)
|
return this.condition.has_side_effects(compressor)
|
||||||
|| this.consequent.has_side_effects(compressor)
|
|| this.consequent.has_side_effects(compressor)
|
||||||
|
|||||||
@@ -45,6 +45,20 @@
|
|||||||
|
|
||||||
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
||||||
|
|
||||||
|
function is_some_comments(comment) {
|
||||||
|
var text = comment.value;
|
||||||
|
var type = comment.type;
|
||||||
|
if (type == "comment2") {
|
||||||
|
// multiline comment
|
||||||
|
return /@preserve|@license|@cc_on/i.test(text);
|
||||||
|
}
|
||||||
|
return type == "comment5";
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_comment5(comment) {
|
||||||
|
return comment.type == "comment5";
|
||||||
|
}
|
||||||
|
|
||||||
function OutputStream(options) {
|
function OutputStream(options) {
|
||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
@@ -81,46 +95,30 @@ function OutputStream(options) {
|
|||||||
options.shorthand = options.ecma > 5;
|
options.shorthand = options.ecma > 5;
|
||||||
|
|
||||||
// Convert comment option to RegExp if neccessary and set up comments filter
|
// Convert comment option to RegExp if neccessary and set up comments filter
|
||||||
if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
|
var comment_filter = options.shebang ? is_comment5 : return_false; // Default case, throw all comments away except shebangs
|
||||||
var regex_pos = options.comments.lastIndexOf("/");
|
if (options.comments) {
|
||||||
options.comments = new RegExp(
|
var comments = options.comments;
|
||||||
options.comments.substr(1, regex_pos - 1),
|
if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
|
||||||
options.comments.substr(regex_pos + 1)
|
var regex_pos = options.comments.lastIndexOf("/");
|
||||||
);
|
comments = new RegExp(
|
||||||
}
|
options.comments.substr(1, regex_pos - 1),
|
||||||
if (options.comments instanceof RegExp) {
|
options.comments.substr(regex_pos + 1)
|
||||||
options.comments = (function(f) {
|
);
|
||||||
return function(comment) {
|
|
||||||
return comment.type == "comment5" || f.test(comment.value);
|
|
||||||
}
|
|
||||||
})(options.comments);
|
|
||||||
}
|
|
||||||
else if (typeof options.comments === "function") {
|
|
||||||
options.comments = (function(f) {
|
|
||||||
return function(comment) {
|
|
||||||
return comment.type == "comment5" || f(this, comment);
|
|
||||||
}
|
|
||||||
})(options.comments);
|
|
||||||
}
|
|
||||||
else if (options.comments === "some") {
|
|
||||||
options.comments = function(comment) {
|
|
||||||
var text = comment.value;
|
|
||||||
var type = comment.type;
|
|
||||||
if (type == "comment2") {
|
|
||||||
// multiline comment
|
|
||||||
return /@preserve|@license|@cc_on/i.test(text);
|
|
||||||
}
|
|
||||||
return type == "comment5";
|
|
||||||
}
|
}
|
||||||
}
|
if (comments instanceof RegExp) {
|
||||||
else if (options.comments){ // NOTE includes "all" option
|
comment_filter = function(comment) {
|
||||||
options.comments = function() {
|
return comment.type == "comment5" || comments.test(comment.value);
|
||||||
return true;
|
};
|
||||||
}
|
}
|
||||||
} else {
|
else if (typeof comments === "function") {
|
||||||
// Falsy case, so reject all comments, except shebangs
|
comment_filter = function(comment) {
|
||||||
options.comments = function(comment) {
|
return comment.type == "comment5" || comments(this, comment);
|
||||||
return comment.type == "comment5";
|
};
|
||||||
|
}
|
||||||
|
else if (comments === "some") {
|
||||||
|
comment_filter = is_some_comments;
|
||||||
|
} else { // NOTE includes "all" option
|
||||||
|
comment_filter = return_true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,6 +468,7 @@ function OutputStream(options) {
|
|||||||
with_square : with_square,
|
with_square : with_square,
|
||||||
add_mapping : add_mapping,
|
add_mapping : add_mapping,
|
||||||
option : function(opt) { return options[opt] },
|
option : function(opt) { return options[opt] },
|
||||||
|
comment_filter : comment_filter,
|
||||||
line : function() { return current_line },
|
line : function() { return current_line },
|
||||||
col : function() { return current_col },
|
col : function() { return current_col },
|
||||||
pos : function() { return current_pos },
|
pos : function() { return current_pos },
|
||||||
@@ -552,7 +551,7 @@ function OutputStream(options) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
comments = comments.filter(output.option("comments"), self);
|
comments = comments.filter(output.comment_filter, self);
|
||||||
|
|
||||||
// Keep single line comments after nlb, after nlb
|
// Keep single line comments after nlb, after nlb
|
||||||
if (!output.option("beautify") && comments.length > 0 &&
|
if (!output.option("beautify") && comments.length > 0 &&
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ function mangle_properties(ast, options) {
|
|||||||
cache : null,
|
cache : null,
|
||||||
only_cache : false,
|
only_cache : false,
|
||||||
regex : null,
|
regex : null,
|
||||||
ignore_quoted : false
|
ignore_quoted : false,
|
||||||
|
debug : false
|
||||||
});
|
});
|
||||||
|
|
||||||
var reserved = options.reserved;
|
var reserved = options.reserved;
|
||||||
@@ -101,6 +102,15 @@ function mangle_properties(ast, options) {
|
|||||||
var regex = options.regex;
|
var regex = options.regex;
|
||||||
var ignore_quoted = options.ignore_quoted;
|
var ignore_quoted = options.ignore_quoted;
|
||||||
|
|
||||||
|
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
|
||||||
|
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
||||||
|
// the same as passing an empty string.
|
||||||
|
var debug = (options.debug !== false);
|
||||||
|
var debug_name_suffix;
|
||||||
|
if (debug) {
|
||||||
|
debug_name_suffix = (options.debug === true ? "" : options.debug);
|
||||||
|
}
|
||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = [];
|
||||||
var unmangleable = [];
|
var unmangleable = [];
|
||||||
var ignored = {};
|
var ignored = {};
|
||||||
@@ -202,9 +212,25 @@ function mangle_properties(ast, options) {
|
|||||||
|
|
||||||
var mangled = cache.props.get(name);
|
var mangled = cache.props.get(name);
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
do {
|
if (debug) {
|
||||||
mangled = base54(++cache.cname);
|
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||||
} while (!can_mangle(mangled));
|
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
||||||
|
|
||||||
|
if (can_mangle(debug_mangled) && !(ignore_quoted && debug_mangled in ignored)) {
|
||||||
|
mangled = debug_mangled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// either debug mode is off, or it is on and we could not use the mangled name
|
||||||
|
if (!mangled) {
|
||||||
|
// note can_mangle() does not check if the name collides with the 'ignored' set
|
||||||
|
// (filled with quoted properties when ignore_quoted set). Make sure we add this
|
||||||
|
// check so we don't collide with a quoted name.
|
||||||
|
do {
|
||||||
|
mangled = base54(++cache.cname);
|
||||||
|
} while (!can_mangle(mangled) || (ignore_quoted && mangled in ignored));
|
||||||
|
}
|
||||||
|
|
||||||
cache.props.set(name, mangled);
|
cache.props.set(name, mangled);
|
||||||
}
|
}
|
||||||
return mangled;
|
return mangled;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ function SourceMap(options) {
|
|||||||
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
||||||
|
|
||||||
if (orig_map && Array.isArray(options.orig.sources)) {
|
if (orig_map && Array.isArray(options.orig.sources)) {
|
||||||
options.orig.sources.forEach(function(source) {
|
orig_map._sources.toArray().forEach(function(source) {
|
||||||
var sourceContent = orig_map.sourceContentFor(source, true);
|
var sourceContent = orig_map.sourceContentFor(source, true);
|
||||||
if (sourceContent) {
|
if (sourceContent) {
|
||||||
generator.setSourceContent(source, sourceContent);
|
generator.setSourceContent(source, sourceContent);
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ function merge(obj, ext) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
|
function return_false() { return false; }
|
||||||
|
function return_true() { return true; }
|
||||||
|
|
||||||
var MAP = (function(){
|
var MAP = (function(){
|
||||||
function MAP(a, f, backwards) {
|
function MAP(a, f, backwards) {
|
||||||
|
|||||||
54
test/compress/issue-1321.js
Normal file
54
test/compress/issue-1321.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
issue_1321_no_debug: {
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var x = {};
|
||||||
|
x.foo = 1;
|
||||||
|
x["a"] = 2 * x.foo;
|
||||||
|
console.log(x.foo, x["a"]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x = {};
|
||||||
|
x.b = 1;
|
||||||
|
x["a"] = 2 * x.b;
|
||||||
|
console.log(x.b, x["a"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1321_debug: {
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: true,
|
||||||
|
debug: ""
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var x = {};
|
||||||
|
x.foo = 1;
|
||||||
|
x["_$foo$_"] = 2 * x.foo;
|
||||||
|
console.log(x.foo, x["_$foo$_"]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x = {};
|
||||||
|
x.a = 1;
|
||||||
|
x["_$foo$_"] = 2 * x.a;
|
||||||
|
console.log(x.a, x["_$foo$_"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1321_with_quoted: {
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: false
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var x = {};
|
||||||
|
x.foo = 1;
|
||||||
|
x["a"] = 2 * x.foo;
|
||||||
|
console.log(x.foo, x["a"]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x = {};
|
||||||
|
x.a = 1;
|
||||||
|
x["b"] = 2 * x.a;
|
||||||
|
console.log(x.a, x["b"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -143,6 +143,98 @@ mangle_unquoted_properties: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mangle_debug: {
|
||||||
|
mangle_props = {
|
||||||
|
debug: ""
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
a.foo = "bar";
|
||||||
|
x = { baz: "ban" };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a._$foo$_ = "bar";
|
||||||
|
x = { _$baz$_: "ban" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_debug_true: {
|
||||||
|
mangle_props = {
|
||||||
|
debug: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
a.foo = "bar";
|
||||||
|
x = { baz: "ban" };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a._$foo$_ = "bar";
|
||||||
|
x = { _$baz$_: "ban" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_debug_suffix: {
|
||||||
|
mangle_props = {
|
||||||
|
debug: "XYZ"
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
a.foo = "bar";
|
||||||
|
x = { baz: "ban" };
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a._$foo$XYZ_ = "bar";
|
||||||
|
x = { _$baz$XYZ_: "ban" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_debug_suffix_ignore_quoted: {
|
||||||
|
options = {
|
||||||
|
properties: false
|
||||||
|
}
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: true,
|
||||||
|
debug: "XYZ",
|
||||||
|
reserved: []
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
quote_style: 3,
|
||||||
|
keep_quoted_props: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a.top = 1;
|
||||||
|
function f1() {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
a.stuff = 2;
|
||||||
|
x = {"bar": 10, size: 7};
|
||||||
|
a.size = 9;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
a.foo = "bar";
|
||||||
|
a['color'] = "red";
|
||||||
|
x = {bar: 10, size: 7};
|
||||||
|
a.size = 9;
|
||||||
|
a.stuff = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a._$top$XYZ_ = 1;
|
||||||
|
function f1() {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
a._$stuff$XYZ_ = 2;
|
||||||
|
x = {"bar": 10, _$size$XYZ_: 7};
|
||||||
|
a._$size$XYZ_ = 9;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
a.foo = "bar";
|
||||||
|
a['color'] = "red";
|
||||||
|
x = {bar: 10, _$size$XYZ_: 7};
|
||||||
|
a._$size$XYZ_ = 9;
|
||||||
|
a._$stuff$XYZ_ = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
first_256_chars_as_properties: {
|
first_256_chars_as_properties: {
|
||||||
beautify = {
|
beautify = {
|
||||||
ascii_only: true,
|
ascii_only: true,
|
||||||
|
|||||||
@@ -15,4 +15,116 @@ dont_screw: {
|
|||||||
|
|
||||||
input: f("\v");
|
input: f("\v");
|
||||||
expect_exact: 'f("\\x0B");';
|
expect_exact: 'f("\\x0B");';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_screw_try_catch: {
|
||||||
|
options = { screw_ie8: true };
|
||||||
|
mangle = { screw_ie8: true };
|
||||||
|
beautify = { screw_ie8: true };
|
||||||
|
input: {
|
||||||
|
good = function(e){
|
||||||
|
return function(error){
|
||||||
|
try{
|
||||||
|
e()
|
||||||
|
} catch(e) {
|
||||||
|
error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
good = function(n){
|
||||||
|
return function(t){
|
||||||
|
try{
|
||||||
|
n()
|
||||||
|
} catch(n) {
|
||||||
|
t(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_screw_try_catch: {
|
||||||
|
options = { screw_ie8: false };
|
||||||
|
mangle = { screw_ie8: false };
|
||||||
|
beautify = { screw_ie8: false };
|
||||||
|
input: {
|
||||||
|
bad = function(e){
|
||||||
|
return function(error){
|
||||||
|
try{
|
||||||
|
e()
|
||||||
|
} catch(e) {
|
||||||
|
error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
bad = function(n){
|
||||||
|
return function(n){
|
||||||
|
try{
|
||||||
|
t()
|
||||||
|
} catch(t) {
|
||||||
|
n(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_screw_try_catch_undefined: {
|
||||||
|
options = { screw_ie8: true };
|
||||||
|
mangle = { screw_ie8: true };
|
||||||
|
beautify = { screw_ie8: true };
|
||||||
|
input: {
|
||||||
|
function a(b){
|
||||||
|
try {
|
||||||
|
throw 'Stuff';
|
||||||
|
} catch (undefined) {
|
||||||
|
console.log('caught: ' + undefined);
|
||||||
|
}
|
||||||
|
console.log('undefined is ' + undefined);
|
||||||
|
return b === undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a(o){
|
||||||
|
try{
|
||||||
|
throw "Stuff"
|
||||||
|
} catch (o) {
|
||||||
|
console.log("caught: "+o)
|
||||||
|
}
|
||||||
|
console.log("undefined is " + void 0);
|
||||||
|
return void 0===o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_screw_try_catch_undefined: {
|
||||||
|
options = { screw_ie8: false };
|
||||||
|
mangle = { screw_ie8: false };
|
||||||
|
beautify = { screw_ie8: false };
|
||||||
|
input: {
|
||||||
|
function a(b){
|
||||||
|
try {
|
||||||
|
throw 'Stuff';
|
||||||
|
} catch (undefined) {
|
||||||
|
console.log('caught: ' + undefined);
|
||||||
|
}
|
||||||
|
console.log('undefined is ' + undefined);
|
||||||
|
return b === undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a(o){
|
||||||
|
try{
|
||||||
|
throw "Stuff"
|
||||||
|
} catch (n) {
|
||||||
|
console.log("caught: "+n)
|
||||||
|
}
|
||||||
|
console.log("undefined is " + void 0);
|
||||||
|
return void 0===o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ var UglifyJS = require('../../');
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
|
|
||||||
describe("comment filters", function() {
|
describe("comment filters", function() {
|
||||||
it("Should be able to filter comments by passing regex", function() {
|
it("Should be able to filter comments by passing regexp", function() {
|
||||||
var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
|
var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
|
||||||
assert.strictEqual(ast.print_to_string({comments: /^!/}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n");
|
assert.strictEqual(ast.print_to_string({comments: /^!/}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n");
|
||||||
});
|
});
|
||||||
@@ -62,4 +62,14 @@ describe("comment filters", function() {
|
|||||||
var ast = UglifyJS.parse("#!foo\n//foo\n/*@preserve*/\n/* please hide me */");
|
var ast = UglifyJS.parse("#!foo\n//foo\n/*@preserve*/\n/* please hide me */");
|
||||||
assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/\n");
|
assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should have no problem on multiple calls", function() {
|
||||||
|
const options = {
|
||||||
|
comments: /ok/
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}");
|
||||||
|
assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}");
|
||||||
|
assert.strictEqual(UglifyJS.parse("/* ok */ function a(){}").print_to_string(options), "/* ok */function a(){}");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,32 +3,55 @@ var assert = require("assert");
|
|||||||
var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
||||||
|
|
||||||
describe("input sourcemaps", function() {
|
describe("input sourcemaps", function() {
|
||||||
var transpiled = '"use strict";\n\n' +
|
var transpilemap, map;
|
||||||
'var foo = function foo(x) {\n return "foo " + x;\n};\n' +
|
|
||||||
'console.log(foo("bar"));\n\n' +
|
|
||||||
'//# sourceMappingURL=bundle.js.map';
|
|
||||||
|
|
||||||
var transpilemap = {
|
function getMap() {
|
||||||
"version": 3,
|
return {
|
||||||
"sources": ["index.js"],
|
"version": 3,
|
||||||
"names": [],
|
"sources": ["index.js"],
|
||||||
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
|
"names": [],
|
||||||
"file": "bundle.js",
|
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
|
||||||
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
|
"file": "bundle.js",
|
||||||
};
|
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
var result = Uglify.minify(transpiled, {
|
function prepareMap(sourceMap) {
|
||||||
fromString: true,
|
var transpiled = '"use strict";\n\n' +
|
||||||
inSourceMap: transpilemap,
|
'var foo = function foo(x) {\n return "foo " + x;\n};\n' +
|
||||||
outSourceMap: true
|
'console.log(foo("bar"));\n\n' +
|
||||||
|
'//# sourceMappingURL=bundle.js.map';
|
||||||
|
|
||||||
|
transpilemap = sourceMap || getMap();
|
||||||
|
|
||||||
|
var result = Uglify.minify(transpiled, {
|
||||||
|
fromString: true,
|
||||||
|
inSourceMap: transpilemap,
|
||||||
|
outSourceMap: true
|
||||||
|
});
|
||||||
|
|
||||||
|
map = new SourceMapConsumer(result.map);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
prepareMap();
|
||||||
});
|
});
|
||||||
var map = new SourceMapConsumer(result.map);
|
|
||||||
|
|
||||||
it("Should copy over original sourcesContent", function() {
|
it("Should copy over original sourcesContent", function() {
|
||||||
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
|
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882) ", function() {
|
it("Should copy sourcesContent if sources are relative", function () {
|
||||||
|
var relativeMap = getMap();
|
||||||
|
relativeMap.sources = ['./index.js'];
|
||||||
|
|
||||||
|
prepareMap(relativeMap);
|
||||||
|
assert.notEqual(map.sourcesContent, null);
|
||||||
|
assert.equal(map.sourcesContent.length, 1);
|
||||||
|
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882)", function() {
|
||||||
// The original source has only 2 lines, check that mappings don't have more lines
|
// The original source has only 2 lines, check that mappings don't have more lines
|
||||||
|
|
||||||
var msg = "Mapping should not have higher line number than the original file had";
|
var msg = "Mapping should not have higher line number than the original file had";
|
||||||
|
|||||||
@@ -7,10 +7,18 @@ describe("Input file as map", function() {
|
|||||||
'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'
|
'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'
|
||||||
};
|
};
|
||||||
var result = Uglify.minify(jsMap, {fromString: true, outSourceMap: true});
|
var result = Uglify.minify(jsMap, {fromString: true, outSourceMap: true});
|
||||||
|
|
||||||
var map = JSON.parse(result.map);
|
var map = JSON.parse(result.map);
|
||||||
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
|
||||||
assert.deepEqual(map.sources, ['/scripts/foo.js']);
|
assert.deepEqual(map.sources, ['/scripts/foo.js']);
|
||||||
|
assert.strictEqual(map.file, undefined);
|
||||||
|
|
||||||
|
result = Uglify.minify(jsMap, {fromString: true, outFileName: 'out.js'});
|
||||||
|
assert.strictEqual(result.map, null);
|
||||||
|
|
||||||
|
result = Uglify.minify(jsMap, {fromString: true, outFileName: 'out.js', outSourceMap: true});
|
||||||
|
map = JSON.parse(result.map);
|
||||||
|
assert.strictEqual(map.file, 'out.js');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should accept array of objects and strings", function() {
|
it("Should accept array of objects and strings", function() {
|
||||||
@@ -19,7 +27,7 @@ describe("Input file as map", function() {
|
|||||||
'var bar = 15;'
|
'var bar = 15;'
|
||||||
];
|
];
|
||||||
var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true});
|
var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true});
|
||||||
|
|
||||||
var map = JSON.parse(result.map);
|
var map = JSON.parse(result.map);
|
||||||
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
|
||||||
assert.strictEqual(map.sources[0], '/scripts/foo.js');
|
assert.strictEqual(map.sources[0], '/scripts/foo.js');
|
||||||
@@ -31,7 +39,7 @@ describe("Input file as map", function() {
|
|||||||
'var bar = 15;'
|
'var bar = 15;'
|
||||||
];
|
];
|
||||||
var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true, sourceMapIncludeSources: true});
|
var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true, sourceMapIncludeSources: true});
|
||||||
|
|
||||||
var map = JSON.parse(result.map);
|
var map = JSON.parse(result.map);
|
||||||
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
|
||||||
assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};', 'var bar = 15;']);
|
assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};', 'var bar = 15;']);
|
||||||
|
|||||||
@@ -63,13 +63,14 @@ describe("minify", function() {
|
|||||||
describe("inSourceMap", function() {
|
describe("inSourceMap", function() {
|
||||||
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
|
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
|
||||||
var result = Uglify.minify('./test/input/issue-1236/simple.js', {
|
var result = Uglify.minify('./test/input/issue-1236/simple.js', {
|
||||||
outSourceMap: "simple.js.min.map",
|
outSourceMap: "simple.min.js.map",
|
||||||
inSourceMap: "./test/input/issue-1236/simple.js.map",
|
inSourceMap: "./test/input/issue-1236/simple.js.map",
|
||||||
sourceMapIncludeSources: true
|
sourceMapIncludeSources: true
|
||||||
});
|
});
|
||||||
|
|
||||||
var map = JSON.parse(result.map);
|
var map = JSON.parse(result.map);
|
||||||
|
|
||||||
|
assert.equal(map.file, 'simple.min.js');
|
||||||
assert.equal(map.sourcesContent.length, 1);
|
assert.equal(map.sourcesContent.length, 1);
|
||||||
assert.equal(map.sourcesContent[0],
|
assert.equal(map.sourcesContent[0],
|
||||||
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
||||||
|
|||||||
23
test/mocha/screw-ie8.js
Normal file
23
test/mocha/screw-ie8.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("screw-ie8", function () {
|
||||||
|
it("Should be able to minify() with undefined as catch parameter in a try...catch statement", function () {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(
|
||||||
|
"function a(b){\
|
||||||
|
try {\
|
||||||
|
throw 'Stuff';\
|
||||||
|
} catch (undefined) {\
|
||||||
|
console.log('caught: ' + undefined);\
|
||||||
|
}\
|
||||||
|
console.log('undefined is ' + undefined);\
|
||||||
|
return b === undefined;\
|
||||||
|
};", {
|
||||||
|
fromString: true
|
||||||
|
}
|
||||||
|
).code,
|
||||||
|
'function a(o){try{throw"Stuff"}catch(o){console.log("caught: "+o)}return console.log("undefined is "+void 0),void 0===o}'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -117,7 +117,7 @@ function run_compress_tests() {
|
|||||||
input = U.mangle_properties(input, test.mangle_props);
|
input = U.mangle_properties(input, test.mangle_props);
|
||||||
}
|
}
|
||||||
var output = cmp.compress(input);
|
var output = cmp.compress(input);
|
||||||
output.figure_out_scope();
|
output.figure_out_scope(test.mangle);
|
||||||
if (test.mangle) {
|
if (test.mangle) {
|
||||||
output.compute_char_frequency(test.mangle);
|
output.compute_char_frequency(test.mangle);
|
||||||
output.mangle_names(test.mangle);
|
output.mangle_names(test.mangle);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ exports.minify = function(files, options) {
|
|||||||
options = UglifyJS.defaults(options, {
|
options = UglifyJS.defaults(options, {
|
||||||
spidermonkey : false,
|
spidermonkey : false,
|
||||||
outSourceMap : null,
|
outSourceMap : null,
|
||||||
|
outFileName : null,
|
||||||
sourceRoot : null,
|
sourceRoot : null,
|
||||||
inSourceMap : null,
|
inSourceMap : null,
|
||||||
sourceMapUrl : null,
|
sourceMapUrl : null,
|
||||||
@@ -120,7 +121,8 @@ exports.minify = function(files, options) {
|
|||||||
}
|
}
|
||||||
if (options.outSourceMap || options.sourceMapInline) {
|
if (options.outSourceMap || options.sourceMapInline) {
|
||||||
output.source_map = UglifyJS.SourceMap({
|
output.source_map = UglifyJS.SourceMap({
|
||||||
file: options.outSourceMap,
|
// prefer outFileName, otherwise use outSourceMap without .map suffix
|
||||||
|
file: options.outFileName || (typeof options.outSourceMap === 'string' ? options.outSourceMap.replace(/\.map$/i, '') : null),
|
||||||
orig: inMap,
|
orig: inMap,
|
||||||
root: options.sourceRoot
|
root: options.sourceRoot
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user