Skip to content

Commit

Permalink
Don't mutate options object. Fixes terser#1341
Browse files Browse the repository at this point in the history
  • Loading branch information
robhogan committed Feb 17, 2023
1 parent e0acb3c commit 05a375f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 11 deletions.
25 changes: 14 additions & 11 deletions lib/minify.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,13 @@ async function minify(files, options, _fs_module) {
if (options.format.spidermonkey) {
result.ast = toplevel.to_mozilla_ast();
}
let format_options;
if (!HOP(options.format, "code") || options.format.code) {
if (!options.format.ast) {
// Make a shallow copy so that we can modify without mutating the user's input.
format_options = {...options.format};
if (!format_options.ast) {
// Destroy stuff to save RAM. (unless the deprecated `ast` option is on)
options.format._destroy_ast = true;
format_options._destroy_ast = true;

walk(toplevel, node => {
if (node instanceof AST_Scope) {
Expand All @@ -303,25 +306,25 @@ async function minify(files, options, _fs_module) {
if (options.sourceMap.includeSources && files instanceof AST_Toplevel) {
throw new Error("original source content unavailable");
}
options.format.source_map = await SourceMap({
format_options.source_map = await SourceMap({
file: options.sourceMap.filename,
orig: options.sourceMap.content,
root: options.sourceMap.root,
files: options.sourceMap.includeSources ? files : null,
});
}
delete options.format.ast;
delete options.format.code;
delete options.format.spidermonkey;
var stream = OutputStream(options.format);
delete format_options.ast;
delete format_options.code;
delete format_options.spidermonkey;
var stream = OutputStream(format_options);
toplevel.print(stream);
result.code = stream.get();
if (options.sourceMap) {
Object.defineProperty(result, "map", {
configurable: true,
enumerable: true,
get() {
const map = options.format.source_map.getEncoded();
const map = format_options.source_map.getEncoded();
return (result.map = options.sourceMap.asObject ? map : JSON.stringify(map));
},
set(value) {
Expand All @@ -331,7 +334,7 @@ async function minify(files, options, _fs_module) {
});
}
});
result.decoded_map = options.format.source_map.getDecoded();
result.decoded_map = format_options.source_map.getDecoded();
if (options.sourceMap.url == "inline") {
var sourceMap = typeof result.map === "object" ? JSON.stringify(result.map) : result.map;
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(sourceMap);
Expand All @@ -346,8 +349,8 @@ async function minify(files, options, _fs_module) {
options.nameCache.props = cache_to_json(options.mangle.properties.cache);
}
}
if (options.format && options.format.source_map) {
options.format.source_map.destroy();
if (format_options && format_options.source_map) {
format_options.source_map.destroy();
}
if (timings) {
timings.end = Date.now();
Expand Down
34 changes: 34 additions & 0 deletions test/mocha/no-mutate-input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import assert from "assert";
import { minify } from "../../main.js";

describe("no-mutate-input", function() {

it("does not modify the options object", async function() {
const config = {
format: {},
sourceMap: true,
};

await minify('"foo";', config);

assert.deepEqual(config, {
format: {},
sourceMap: true,
});
});

it("does not clobber source maps with a subsequent minification", async function() {
const config = {
format: {},
sourceMap: true,
};

const fooResult = await minify('"foo";', config);
const barResult = await minify('module.exports = "bar";', config);

const fooMap = fooResult.map;
const barMap = barResult.map;

assert.notEqual(barMap, fooMap);
});
});

0 comments on commit 05a375f

Please sign in to comment.