From 7de8ffe77b6e5ffeb29f6aea8b19f339766b8782 Mon Sep 17 00:00:00 2001 From: "Ashley (Scirra)" Date: Thu, 6 Oct 2016 16:42:23 +0100 Subject: [PATCH] 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). --- README.md | 18 ++++----- bin/uglifyjs | 6 +-- lib/propmangle.js | 17 ++++---- test/compress/properties.js | 78 +++++++++++++++++++++++++++++++++++++ test/mocha/mangle-debug.js | 22 ----------- 5 files changed, 99 insertions(+), 42 deletions(-) delete mode 100644 test/mocha/mangle-debug.js diff --git a/README.md b/README.md index cd9a99db..4fc9083b 100644 --- a/README.md +++ b/README.md @@ -288,18 +288,16 @@ single call to UglifyJS. You can also pass `--mangle-debug` in order to mangle property names 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 where mangling is breaking things. -Note that by default a random number is added to the name per invocation, -e.g. the `123` in `_$foo$123_` is random. This is because normal property -mangling is non-deterministic. It makes sure that if you mangle two scripts -separately without sharing a cache, they will be broken. It also makes sure -that if you accidentally attempt to use a mangled key name in storage, then -the storage reads will be broken between builds. This allows you to fix these -issues with readable keys, and then turning off this option should continue to -work with unreadable names. +You can also pass a custom suffix using `--mangle-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 @@ -760,7 +758,7 @@ Other options: - `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) - - `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 functionality please suggest! diff --git a/bin/uglifyjs b/bin/uglifyjs index cf99faed..733c9a91 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -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("reserved-file", "File containing reserved names") .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-regex", "Only mangle property names matching the regex") .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("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.") - .describe("mangle-debug", "Use debug mode for diagnosing property mangling errors.") .alias("p", "prefix") .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("m") .string("mangle") + .string("mangle-debug") .string("c") .string("compress") .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("keep-fnames") .boolean("reserve-domprops") - .boolean("mangle-debug") .wrap(80) @@ -428,7 +428,7 @@ async.eachLimit(files, 1, function (file, cb) { only_cache : !ARGS.mangle_props, regex : regex, ignore_quoted : ARGS.mangle_props == 2, - debug : ARGS.mangle_debug + debug : typeof ARGS.mangle_debug === "undefined" ? false : ARGS.mangle_debug }); writeNameCache("props", cache); })(); diff --git a/lib/propmangle.js b/lib/propmangle.js index eac51b44..4d29b3d0 100644 --- a/lib/propmangle.js +++ b/lib/propmangle.js @@ -90,7 +90,7 @@ function mangle_properties(ast, options) { var reserved = options.reserved; if (reserved == null) reserved = find_builtins(); - + var cache = options.cache; if (cache == null) { cache = { @@ -101,10 +101,13 @@ function mangle_properties(ast, options) { var regex = options.regex; 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 - var debug_cache_name = Math.floor(Math.random() * 1000).toString(); + // note debug is either false (disabled), or a string of the debug cache name to use (enabled). + // 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 unmangleable = []; @@ -213,10 +216,10 @@ function mangle_properties(ast, options) { if (can_mangle(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 { mangled = base54(++cache.cname); } while (!can_mangle(mangled)); diff --git a/test/compress/properties.js b/test/compress/properties.js index 7ef6a014..554dd4d2 100644 --- a/test/compress/properties.js +++ b/test/compress/properties.js @@ -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: { beautify = { ascii_only: true, diff --git a/test/mocha/mangle-debug.js b/test/mocha/mangle-debug.js deleted file mode 100644 index 122245a7..00000000 --- a/test/mocha/mangle-debug.js +++ /dev/null @@ -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)); - }); -});