Make debug option take a string suffix

Debug option (and CLI) now take a string to enable, and the string is
used as the (possibly empty) suffix. Instead of generating a random
number, the caller can do that if they wish. Updated tests accordingly
(no need for regex now).
This commit is contained in:
Ashley (Scirra) 2016-10-06 16:42:23 +01:00
parent b28d2d3cf2
commit 7de8ffe77b
5 changed files with 99 additions and 42 deletions

View File

@ -288,18 +288,16 @@ single call to UglifyJS.
You can also pass `--mangle-debug` in order to mangle property names You can also pass `--mangle-debug` in order to mangle property names
without completely obscuring them. For example the property `o.foo` without completely obscuring them. For example the property `o.foo`
would mangle to `o._$foo$123_` with this option. This allows property mangling 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 of a large codebase while still being able to debug the code and identify
where mangling is breaking things. where mangling is breaking things.
Note that by default a random number is added to the name per invocation, You can also pass a custom suffix using `--mangle-debug=XYZ`. This would then
e.g. the `123` in `_$foo$123_` is random. This is because normal property mangle `o.foo` to `o._$foo$XYZ_`. You can change this each time you compile a
mangling is non-deterministic. It makes sure that if you mangle two scripts script to identify how a property got mangled. One technique is to pass a
separately without sharing a cache, they will be broken. It also makes sure random number on every compile to simulate mangling changing with different
that if you accidentally attempt to use a mangled key name in storage, then inputs (e.g. as you update the input script with new properties), and to help
the storage reads will be broken between builds. This allows you to fix these identify mistakes like writing mangled keys to storage.
issues with readable keys, and then turning off this option should continue to
work with unreadable names.
## Compressor options ## Compressor options
@ -760,7 +758,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-debug` CLI arguments option) - `debug` Mangle names with the original name still present (maps to the `--mangle-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!

View File

@ -71,12 +71,12 @@ You need to pass an argument to this option to specify the name that your module
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)") .describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
.describe("reserved-file", "File containing reserved names") .describe("reserved-file", "File containing reserved names")
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props") .describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
.describe("mangle-debug", "Use debug mode for diagnosing property mangling errors. Optionally provide a mangled name suffix.")
.describe("mangle-props", "Mangle property names (0 - disabled, 1 - mangle all properties, 2 - mangle unquoted properies)") .describe("mangle-props", "Mangle property names (0 - disabled, 1 - mangle all properties, 2 - mangle unquoted properies)")
.describe("mangle-regex", "Only mangle property names matching the regex") .describe("mangle-regex", "Only mangle property names matching the regex")
.describe("name-cache", "File to hold mangled names mappings") .describe("name-cache", "File to hold mangled names mappings")
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used") .describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.") .describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
.describe("mangle-debug", "Use debug mode for diagnosing property mangling errors.")
.alias("p", "prefix") .alias("p", "prefix")
.alias("o", "output") .alias("o", "output")
@ -97,6 +97,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-debug")
.string("c") .string("c")
.string("compress") .string("compress")
.string("d") .string("d")
@ -131,7 +132,6 @@ You need to pass an argument to this option to specify the name that your module
.boolean("bare-returns") .boolean("bare-returns")
.boolean("keep-fnames") .boolean("keep-fnames")
.boolean("reserve-domprops") .boolean("reserve-domprops")
.boolean("mangle-debug")
.wrap(80) .wrap(80)
@ -428,7 +428,7 @@ async.eachLimit(files, 1, function (file, cb) {
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 : ARGS.mangle_debug debug : typeof ARGS.mangle_debug === "undefined" ? false : ARGS.mangle_debug
}); });
writeNameCache("props", cache); writeNameCache("props", cache);
})(); })();

View File

@ -90,7 +90,7 @@ function mangle_properties(ast, options) {
var reserved = options.reserved; var reserved = options.reserved;
if (reserved == null) if (reserved == null)
reserved = find_builtins(); reserved = find_builtins();
var cache = options.cache; var cache = options.cache;
if (cache == null) { if (cache == null) {
cache = { cache = {
@ -101,10 +101,13 @@ 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;
var debug = options.debug;
// Simulate non-deterministic mangling in debug mode by adding a random number to the name // note debug is either false (disabled), or a string of the debug cache name to use (enabled).
var debug_cache_name = Math.floor(Math.random() * 1000).toString(); // note debug may be enabled as an empty string, which is falsey.
var debug = (options.debug !== false);
var debug_cache_name;
if (debug)
debug_cache_name = options.debug;
var names_to_mangle = []; var names_to_mangle = [];
var unmangleable = []; var unmangleable = [];
@ -213,10 +216,10 @@ function mangle_properties(ast, options) {
if (can_mangle(debug_mangled)) if (can_mangle(debug_mangled))
mangled = debug_mangled; mangled = debug_mangled;
else
mangled = name;
} }
else {
// either debug mode is off, or it is on and can_mangle returned false
if (!mangled) {
do { do {
mangled = base54(++cache.cname); mangled = base54(++cache.cname);
} while (!can_mangle(mangled)); } while (!can_mangle(mangled));

View File

@ -143,6 +143,84 @@ mangle_unquoted_properties: {
} }
} }
mangle_debug: {
mangle_props = {
debug: ""
};
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,

View File

@ -1,22 +0,0 @@
var Uglify = require('../../');
var assert = require("assert");
describe("mangle_properties 'debug' option ", function() {
it("Should test the 'debug' option of mangle_properties works as expected", function() {
var js = 'var o = {}; o.foo = "bar";';
var ast = Uglify.parse(js);
ast.figure_out_scope();
ast = Uglify.mangle_properties(ast, {
debug: true
});
var stream = Uglify.OutputStream();
ast.print(stream);
var result = stream.toString();
// Should match: var o={};o._$foo$NNN="bar";
// where NNN is a number.
assert(/var o=\{\};o\._\$foo\$\d+_="bar";/.test(result));
});
});