diff --git a/lib/minify.js b/lib/minify.js index a68cbf3a..7ddfbeff 100644 --- a/lib/minify.js +++ b/lib/minify.js @@ -120,7 +120,7 @@ function minify(files, options) { if (typeof files == "string") { files = [ files ]; } - options.parse = options.parse || {}; + options.parse = assign({}, options.parse); options.parse.toplevel = null; for (var name in files) if (HOP(files, name)) { options.parse.filename = name; @@ -159,6 +159,7 @@ function minify(files, options) { toplevel = mangle_properties(toplevel, options.mangle.properties); } if (timings) timings.output = Date.now(); + options.output = assign({}, options.output); var result = {}; if (options.output.ast) { result.ast = toplevel; diff --git a/lib/scope.js b/lib/scope.js index 6c883c66..e13e7f4b 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -405,7 +405,7 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) { reserved : [], toplevel : false, }); - if (!Array.isArray(options.reserved)) options.reserved = []; + options.reserved = Array.isArray(options.reserved) ? options.reserved.slice() : []; // Never mangle arguments push_uniq(options.reserved, "arguments"); return options; diff --git a/lib/utils.js b/lib/utils.js index 9121fa93..03e2a743 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -95,15 +95,14 @@ DefaultsError.croak = function(msg, defs) { }; function defaults(args, defs, croak) { - 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); - for (var i in defs) if (HOP(defs, i)) { - ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; + if (args === true || !args) return defs; + + for (var i in args) if (HOP(args, i)) { + if (croak && !HOP(defs, i)) + DefaultsError.croak("`" + i + "` is not a supported option", defs); + defs[i] = args[i]; } - return ret; + return defs; }; function merge(obj, ext) { @@ -115,6 +114,11 @@ function merge(obj, ext) { return count; }; +function assign(obj, ext) { + merge(obj, ext); + return obj; +}; + function noop() {} function return_false() { return false; } function return_true() { return true; } diff --git a/test/mocha/minify.js b/test/mocha/minify.js index 65392ee4..01e0eb46 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -122,6 +122,32 @@ describe("minify", function() { assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)"); }); + it("Should not mutate options", function() { + [ + {}, + { + parse: {}, + compress: { + global_defs: {}, + }, + mangle: { + reserved: [], + // expect `cache` to be mutated + }, + output: {}, + rename: { + reserved: [], + }, + sourceMap: {}, + // expect `nameCache` to be mutated + }, + ].forEach(function(options) { + var optsString = JSON.stringify(options); + Uglify.minify("", options); + assert.strictEqual(JSON.stringify(options), optsString); + }); + }); + describe("keep_quoted_props", function() { it("Should preserve quotes in object literals", function() { var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';