From c7f5c6b36bd85c7f781174ba072e4b81f16a5c4d Mon Sep 17 00:00:00 2001 From: Anat Dagan Date: Thu, 9 Feb 2017 13:31:51 +0200 Subject: [PATCH 1/2] add --illegalmangled option. list of names that are not o be assigned to vars during mangle/propmangle. added javascript reserved words as default. This fixes current issue that in some constalations uglify-js mangles properties to js reserved words e.g. if --- README.md | 11 +++++ bin/uglifyjs | 9 ++++ lib/propmangle.js | 65 ++++++++++++++++++++++++++++- lib/scope.js | 6 ++- test/mocha/illegal_mangled_names.js | 65 +++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 test/mocha/illegal_mangled_names.js diff --git a/README.md b/README.md index a8b55843..1185df98 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ The available options are: -b, --beautify Beautify output/specify output options. -m, --mangle Mangle names/pass mangler options. -r, --reserved Reserved names to exclude from mangling. + --illegalmangled Reserved names to avoid when choosing the mangled name. -c, --compress Enable compressor/pass compressor options. Pass options like -c hoist_vars=false,if_return=false. Use -c with @@ -221,6 +222,16 @@ comma-separated list of names. For example: to prevent the `require`, `exports` and `$` names from being changed. +When mangling is enabled but you want to prevent certain names from being +chosen as variable names after mangle, you can declare those names with `--illegalmangled — pass a +comma-separated list of names. For example: + + uglifyjs ... -m -r '$,if,in,to' + +to prevent the `if`, `in` and `to` names from being assigned to variables. +By default the illegal mangled list contains the javascript reserved words. +If you don't want any limitation, you can pass '.' + ### Mangling property names (`--mangle-props`) **Note:** this will probably break your code. Mangling property names is a diff --git a/bin/uglifyjs b/bin/uglifyjs index 8cb2f0df..49f4dff8 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -37,6 +37,7 @@ the source map and the output file.") .describe("b", "Beautify output/specify output options.") .describe("m", "Mangle names/pass mangler options.") .describe("r", "Reserved names to exclude from mangling.") + .describe("illegalmangled" , "Reserved names to avoid when choosing the mangled name.") .describe("c", "Enable compressor/pass compressor options. \ Pass options like -c hoist_vars=false,if_return=false. \ Use -c with no argument to use the default compression options.") @@ -174,6 +175,7 @@ var COMPRESS = getOptions("c", true); var MANGLE = getOptions("m", true); var BEAUTIFY = getOptions("b", true); var RESERVED = null; +var ILLEGALMANGLED = null; if (ARGS.reserved_file) ARGS.reserved_file.forEach(function(filename){ RESERVED = UglifyJS.readReservedFile(filename, RESERVED); @@ -194,6 +196,12 @@ if (ARGS.pure_funcs) { if (ARGS.r) { if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/); } +if (ARGS.illegalmangled) { + ILLEGALMANGLED = (ARGS.illegalmangled === ".")? [] : ARGS.illegalmangled.replace(/^\s+|\s+$/g).split(/\s*,+\s*/); + if (MANGLE) { + MANGLE.illegalmangled = ILLEGALMANGLED; + } +} if (RESERVED && MANGLE) { if (!MANGLE.except) MANGLE.except = RESERVED.vars; @@ -417,6 +425,7 @@ async.eachLimit(files, 1, function (file, cb) { TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, { reserved : reserved, + illegalmangled: ILLEGALMANGLED, cache : cache, only_cache : !ARGS.mangle_props, regex : regex, diff --git a/lib/propmangle.js b/lib/propmangle.js index f2777475..f50b4cc4 100644 --- a/lib/propmangle.js +++ b/lib/propmangle.js @@ -59,6 +59,63 @@ function find_builtins() { } return a; } +function find_js_reserved_words() { + return ["abstract", "else", "instanceof", "super", + "boolean", "enum", "int", "switch", + "break", "export", "interface", "synchronized", + "byte", "extends", "let", "this", + "case", "false", "long", "throw", + "catch", "final", "native", "throws", + "char", "finally", "new", "transient", + "class", "float", "null", "true", + "const", "for", "package", "try", + "continue", "function", "private", "typeof", + "debugger", "goto", "protected", "var", + "default", "if", "public", "void", + "delete", "implements", "return", "volatile", + "do", "import", "short", "while", + "double", "in", "static", "with", "alert", "frames", "outerHeight", + "all", "frameRate", "outerWidth", + "anchor", "function", "packages", + "anchors", "getClass", "pageXOffset", + "area", "hasOwnProperty", "pageYOffset", + "Array", "hidden", "parent", + "assign", "history", "parseFloat", + "blur", "image", "parseInt", + "button", "images", "password", + "checkbox", "Infinity", "pkcs11", + "clearInterval", "isFinite", "plugin", + "clearTimeout", "isNaN", "prompt", + "clientInformation", "isPrototypeOf", "propertyIsEnum", + "close", "java", "prototype", + "closed", "JavaArray", "radio", + "confirm", "JavaClass", "reset", + "constructor", "JavaObject", "screenX", + "crypto", "JavaPackage", "screenY", + "Date", "innerHeight", "scroll", + "decodeURI", "innerWidth", "secure", + "decodeURIComponent", "layer", "select", + "defaultStatus", "layers", "self", + "document", "length", "setInterval", + "element", "link", "setTimeout", + "elements", "location", "status", + "embed", "Math", "String", + "embeds", "mimeTypes", "submit", + "encodeURI", "name", "taint", + "encodeURIComponent", "NaN", "text", + "escape", "navigate", "textarea", + "eval", "navigator", "top", + "event", "Number", "toString", + "fileUpload", "Object", "undefined", + "focus", "offscreenBuffering", "unescape", + "form", "open", "untaint", + "forms", "opener", "valueOf", + "frame", "option", "window", "onbeforeunload", "ondragdrop", "onkeyup", "onmouseover", + "onblur", "onerror", "onload", "onmouseup", + "ondragdrop", "onfocus", "onmousedown", "onreset", + "onclick", "onkeydown", "onmousemove", "onsubmit", + "oncontextmenu", "onkeypress", "onmouseout", "onunload"]; +} function mangle_properties(ast, options) { options = defaults(options, { @@ -67,13 +124,16 @@ function mangle_properties(ast, options) { only_cache : false, regex : null, ignore_quoted : false, + illegal_mangled_names: null, debug : false }); var reserved = options.reserved; if (reserved == null) reserved = find_builtins(); - + var illegal_mangled_names = options.illegal_mangled_names; + if (illegal_mangled_names == null) + illegal_mangled_names = find_js_reserved_words(); var cache = options.cache; if (cache == null) { cache = { @@ -98,6 +158,9 @@ function mangle_properties(ast, options) { var unmangleable = []; var ignored = {}; + if (illegal_mangled_names) { + unmangleable = unmangleable.concat(illegal_mangled_names); + } // step 1: find candidates to mangle ast.walk(new TreeWalker(function(node){ if (node instanceof AST_ObjectKeyVal) { diff --git a/lib/scope.js b/lib/scope.js index 55d1eff1..8d3f43cc 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -306,8 +306,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){ AST_Scope.DEFMETHOD("next_mangled", function(options){ var ext = this.enclosed; + var illegal_mangled_names = options.illegal_mangled_names || []; out: while (true) { var m = base54(++this.cname); + if (illegal_mangled_names.indexOf(m) !== -1) continue; //this name is illegal if (!is_identifier(m)) continue; // skip over "do" // https://github.com/mishoo/UglifyJS2/issues/242 -- do not @@ -395,13 +397,15 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ sort : false, // Ignored. Flag retained for backwards compatibility. toplevel : false, screw_ie8 : true, + illegal_mangled_names: null, keep_fnames : false }); }); AST_Toplevel.DEFMETHOD("mangle_names", function(options){ options = this._default_mangler_options(options); - + if (options.illegal_mangled_names == null) + options.illegal_mangled_names = find_js_reserved_words(); // Never mangle arguments options.except.push('arguments'); diff --git a/test/mocha/illegal_mangled_names.js b/test/mocha/illegal_mangled_names.js new file mode 100644 index 00000000..97ad9907 --- /dev/null +++ b/test/mocha/illegal_mangled_names.js @@ -0,0 +1,65 @@ +/** + * Created by anatd on 2/9/2017. + */ +var assert = require("assert"); +var uglify = require("../../"); + +describe("verify that the mangled names are legal", function () { + it("Should not mangle properties to names in the illegal_mangled_names param", function () { + var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};'; + var result = uglify.minify(js, { + fromString: true, + compress: { + properties: false + }, + mangleProperties: { + ignore_quoted: true, + illegal_mangled_names: ["a"] + }, + output: { + keep_quoted_props: true, + quote_style: 3 + } + }); + assert.strictEqual(result.code, + 'a["foo"]="bar",a.b="red",x={"bar":10};'); + }); + it("Should not mangle names to names in the illegal_mangled_names param", function () { + var js = 'var a; a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};'; + var result = uglify.minify(js, { + fromString: true, + compress: { + properties: false + }, + mangleProperties: { + ignore_quoted: true + }, + mangle: {toplevel: true, illegal_mangled_names: ["r", "a"]}, + output: { + keep_quoted_props: true, + quote_style: 3 + } + }); + assert.strictEqual(result.code, + 'var b;b["foo"]="bar",b.a="red",x={"bar":10};'); + }); + it("Should not fail without illegal_mangled_names param", function () { + var js = 'var b; b["foo"] = "bar"; b.color = "red"; x = {"bar": 10};'; + var result = uglify.minify(js, { + fromString: true, + compress: { + properties: false + }, + mangleProperties: { + ignore_quoted: true + }, + mangle: {toplevel: true}, + output: { + keep_quoted_props: true, + quote_style: 3 + } + }); + assert.strictEqual(result.code, + 'var a;a["foo"]="bar",a.a="red",x={"bar":10};'); + }); +}); From d0d37f8e2e93d6de47845e0c6bf0f114192a7cb0 Mon Sep 17 00:00:00 2001 From: Anat Dagan Date: Thu, 9 Feb 2017 13:41:53 +0200 Subject: [PATCH 2/2] rename illegal_mangled_names to illegalmangled --- lib/propmangle.js | 12 ++++++------ lib/scope.js | 10 +++++----- test/mocha/illegal_mangled_names.js | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/propmangle.js b/lib/propmangle.js index f50b4cc4..1eb58550 100644 --- a/lib/propmangle.js +++ b/lib/propmangle.js @@ -124,16 +124,16 @@ function mangle_properties(ast, options) { only_cache : false, regex : null, ignore_quoted : false, - illegal_mangled_names: null, + illegalmangled: null, debug : false }); var reserved = options.reserved; if (reserved == null) reserved = find_builtins(); - var illegal_mangled_names = options.illegal_mangled_names; - if (illegal_mangled_names == null) - illegal_mangled_names = find_js_reserved_words(); + var illegalmangled = options.illegalmangled; + if (illegalmangled == null) + illegalmangled = find_js_reserved_words(); var cache = options.cache; if (cache == null) { cache = { @@ -158,8 +158,8 @@ function mangle_properties(ast, options) { var unmangleable = []; var ignored = {}; - if (illegal_mangled_names) { - unmangleable = unmangleable.concat(illegal_mangled_names); + if (illegalmangled) { + unmangleable = unmangleable.concat(illegalmangled); } // step 1: find candidates to mangle ast.walk(new TreeWalker(function(node){ diff --git a/lib/scope.js b/lib/scope.js index 8d3f43cc..1bb922d3 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -306,10 +306,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){ AST_Scope.DEFMETHOD("next_mangled", function(options){ var ext = this.enclosed; - var illegal_mangled_names = options.illegal_mangled_names || []; + var illegalmangled = options.illegalmangled || []; out: while (true) { var m = base54(++this.cname); - if (illegal_mangled_names.indexOf(m) !== -1) continue; //this name is illegal + if (illegalmangled.indexOf(m) !== -1) continue; //this name is illegal if (!is_identifier(m)) continue; // skip over "do" // https://github.com/mishoo/UglifyJS2/issues/242 -- do not @@ -397,15 +397,15 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ sort : false, // Ignored. Flag retained for backwards compatibility. toplevel : false, screw_ie8 : true, - illegal_mangled_names: null, + illegalmangled: null, keep_fnames : false }); }); AST_Toplevel.DEFMETHOD("mangle_names", function(options){ options = this._default_mangler_options(options); - if (options.illegal_mangled_names == null) - options.illegal_mangled_names = find_js_reserved_words(); + if (options.illegalmangled == null) + options.illegalmangled = find_js_reserved_words(); // Never mangle arguments options.except.push('arguments'); diff --git a/test/mocha/illegal_mangled_names.js b/test/mocha/illegal_mangled_names.js index 97ad9907..b40e17e9 100644 --- a/test/mocha/illegal_mangled_names.js +++ b/test/mocha/illegal_mangled_names.js @@ -5,7 +5,7 @@ var assert = require("assert"); var uglify = require("../../"); describe("verify that the mangled names are legal", function () { - it("Should not mangle properties to names in the illegal_mangled_names param", function () { + it("Should not mangle properties to names in the illegalmangled param", function () { var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};'; var result = uglify.minify(js, { fromString: true, @@ -14,7 +14,7 @@ describe("verify that the mangled names are legal", function () { }, mangleProperties: { ignore_quoted: true, - illegal_mangled_names: ["a"] + illegalmangled: ["a"] }, output: { keep_quoted_props: true, @@ -24,7 +24,7 @@ describe("verify that the mangled names are legal", function () { assert.strictEqual(result.code, 'a["foo"]="bar",a.b="red",x={"bar":10};'); }); - it("Should not mangle names to names in the illegal_mangled_names param", function () { + it("Should not mangle names to names in the illegalmangled param", function () { var js = 'var a; a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};'; var result = uglify.minify(js, { fromString: true, @@ -34,7 +34,7 @@ describe("verify that the mangled names are legal", function () { mangleProperties: { ignore_quoted: true }, - mangle: {toplevel: true, illegal_mangled_names: ["r", "a"]}, + mangle: {toplevel: true, illegalmangled: ["r", "a"]}, output: { keep_quoted_props: true, quote_style: 3 @@ -43,7 +43,7 @@ describe("verify that the mangled names are legal", function () { assert.strictEqual(result.code, 'var b;b["foo"]="bar",b.a="red",x={"bar":10};'); }); - it("Should not fail without illegal_mangled_names param", function () { + it("Should not fail without illegalmangled param", function () { var js = 'var b; b["foo"] = "bar"; b.color = "red"; x = {"bar": 10};'; var result = uglify.minify(js, { fromString: true,