UglifyJS/test/mocha/minify.js

400 lines
15 KiB
JavaScript
Raw Normal View History

var assert = require("assert");
var readFileSync = require("fs").readFileSync;
var run_code = require("../sandbox").run_code;
var semver = require("semver");
var UglifyJS = require("../..");
unify CLI & API under `minify()` (#1811) - rename `screw_ie8` to `ie8` - rename `mangle.except` to `mangle.reserved` - rename `mangle.properties.ignore_quoted` to `mangle.properties.keep_quoted` - compact `sourceMap` options - more stringent verification on input `options` - toplevel shorthands - `ie8` - `keep_fnames` - `toplevel` - `warnings` - support arrays and unquoted string values on CLI - drop `fromString` from `minify()` - `minify()` no longer handles any `fs` operations - unify order of operations for `mangle_properties()` on CLI & API - `bin/uglifyjs` used to `mangle_properties()` before even `Compressor` - `minify()` used to `mangle_properties()` after `Compressor` but before `mangle_names()` - both will now do `Compressor`, `mangle_names()` then `mangle_properties()` - `options.parse` / `--parse` for parser options beyond `bare_returns` - add `mangle.properties.builtins` to disable built-in reserved list - disable with `--mangle-props builtins` on CLI - `warnings` now off by default - add `--warn` and `--verbose` on CLI - drop `--enclose` - drop `--export-all` - drop `--reserved-file` - use `--mangle reserved` instead - drop `--reserve-domprops` - enabled by default, disable with `--mangle-props domprops` - drop `--prefix` - use `--source-map base` instead - drop `--lint` - remove `bin/extract-props.js` - limit exposure of internal APIs - update documentations closes #96 closes #102 closes #136 closes #166 closes #243 closes #254 closes #261 closes #311 closes #700 closes #748 closes #912 closes #1072 closes #1366 fixes #101 fixes #123 fixes #124 fixes #263 fixes #379 fixes #419 fixes #423 fixes #461 fixes #465 fixes #576 fixes #737 fixes #772 fixes #958 fixes #1036 fixes #1142 fixes #1175 fixes #1220 fixes #1223 fixes #1280 fixes #1359 fixes #1368
2017-04-15 15:50:50 +00:00
function read(path) {
return readFileSync(path, "utf8");
}
describe("minify", function() {
it("Should test basic sanity of minify with default options", function() {
var js = "function foo(bar) { if (bar) return 3; else return 7; var u = not_called(); }";
2022-12-04 01:10:32 +00:00
var result = UglifyJS.minify(js);
if (result.error) throw result.error;
assert.strictEqual(result.code, "function foo(n){return n?3:7}");
});
it("Should not mutate minify `options`", function() {
var options = {
compress: true,
mangle: false,
output: {},
};
var value = JSON.stringify(options);
var result = UglifyJS.minify("print(6 * 7);", options);
if (result.error) throw result.error;
assert.strictEqual(result.code, "print(42);");
assert.strictEqual(JSON.stringify(options), value);
});
it("Should skip inherited keys from `files`", function() {
var files = Object.create({ skip: this });
files[0] = "alert(1 + 1)";
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(files);
if (result.error) throw result.error;
assert.strictEqual(result.code, "alert(2);");
});
it("Should work with mangle.cache", function() {
var cache = {};
var original = "";
var compressed = "";
[
"bar.es5",
"baz.es5",
"foo.es5",
"qux.js",
].forEach(function(file) {
var code = read("test/input/issue-1242/" + file);
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
mangle: {
cache: cache,
toplevel: true,
},
});
if (result.error) throw result.error;
original += code;
compressed += result.code;
});
assert.strictEqual(JSON.stringify(cache).slice(0, 10), '{"props":{');
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
2018-02-23 15:51:49 +00:00
"var c=console.log.bind(console);",
'function o(o){c("Foo:",2*o)}',
"var a=n(3),b=r(12);",
2018-02-23 15:51:49 +00:00
'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should work with nameCache", function() {
var cache = {};
var original = "";
var compressed = "";
[
"bar.es5",
"baz.es5",
"foo.es5",
"qux.js",
].forEach(function(file) {
var code = read("test/input/issue-1242/" + file);
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
mangle: {
toplevel: true,
},
nameCache: cache,
});
if (result.error) throw result.error;
original += code;
compressed += result.code;
});
assert.strictEqual(JSON.stringify(cache).slice(0, 18), '{"vars":{"props":{');
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
2018-02-23 15:51:49 +00:00
"var c=console.log.bind(console);",
'function o(o){c("Foo:",2*o)}',
"var a=n(3),b=r(12);",
2018-02-23 15:51:49 +00:00
'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should avoid cached names when mangling top-level variables", function() {
var cache = {};
var original = "";
var compressed = "";
[
'"xxxyy";var i={s:1};',
'"xxyyy";var j={t:2,u:3},k=4;',
'console.log(i.s,j.t,j.u,k);',
].forEach(function(code) {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
compress: false,
mangle: {
properties: {
domprops: true,
},
toplevel: true,
},
nameCache: cache,
});
if (result.error) throw result.error;
original += code;
compressed += result.code;
});
assert.strictEqual(compressed, [
'"xxxyy";var x={x:1};',
'"xxyyy";var y={y:2,a:3},a=4;',
'console.log(x.x,y.y,y.a,a);',
].join(""));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should avoid cached names when mangling inner-scoped variables", function() {
var cache = {};
var original = "";
var compressed = "";
[
'var extend = function(a, b) { console.log("extend"); a(); b(); }; function A() { console.log("A"); };',
'var B = function(A) { function B() { console.log("B") }; extend(B, A); return B; }(A);',
].forEach(function(code) {
var result = UglifyJS.minify(code, {
compress: false,
nameCache: cache,
toplevel: true,
});
if (result.error) throw result.error;
original += code;
compressed += result.code;
});
assert.strictEqual(compressed, [
'var o=function(o,n){console.log("extend");o();n()};function n(){console.log("A")}',
'var e=function(n){function e(){console.log("B")}o(e,n);return e}(n);',
].join(""));
assert.strictEqual(run_code(compressed, true), run_code(original, true));
});
it("Should not parse invalid use of reserved words", function() {
2018-06-21 17:04:15 +00:00
assert.strictEqual(UglifyJS.minify("function enum(){}").error, undefined);
assert.strictEqual(UglifyJS.minify("function static(){}").error, undefined);
assert.strictEqual(UglifyJS.minify("function this(){}").error.message, "Unexpected token: name «this»");
});
describe("keep_quoted_props", function() {
it("Should preserve quotes in object literals", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(js, {
unify CLI & API under `minify()` (#1811) - rename `screw_ie8` to `ie8` - rename `mangle.except` to `mangle.reserved` - rename `mangle.properties.ignore_quoted` to `mangle.properties.keep_quoted` - compact `sourceMap` options - more stringent verification on input `options` - toplevel shorthands - `ie8` - `keep_fnames` - `toplevel` - `warnings` - support arrays and unquoted string values on CLI - drop `fromString` from `minify()` - `minify()` no longer handles any `fs` operations - unify order of operations for `mangle_properties()` on CLI & API - `bin/uglifyjs` used to `mangle_properties()` before even `Compressor` - `minify()` used to `mangle_properties()` after `Compressor` but before `mangle_names()` - both will now do `Compressor`, `mangle_names()` then `mangle_properties()` - `options.parse` / `--parse` for parser options beyond `bare_returns` - add `mangle.properties.builtins` to disable built-in reserved list - disable with `--mangle-props builtins` on CLI - `warnings` now off by default - add `--warn` and `--verbose` on CLI - drop `--enclose` - drop `--export-all` - drop `--reserved-file` - use `--mangle reserved` instead - drop `--reserve-domprops` - enabled by default, disable with `--mangle-props domprops` - drop `--prefix` - use `--source-map base` instead - drop `--lint` - remove `bin/extract-props.js` - limit exposure of internal APIs - update documentations closes #96 closes #102 closes #136 closes #166 closes #243 closes #254 closes #261 closes #311 closes #700 closes #748 closes #912 closes #1072 closes #1366 fixes #101 fixes #123 fixes #124 fixes #263 fixes #379 fixes #419 fixes #423 fixes #461 fixes #465 fixes #576 fixes #737 fixes #772 fixes #958 fixes #1036 fixes #1142 fixes #1175 fixes #1220 fixes #1223 fixes #1280 fixes #1359 fixes #1368
2017-04-15 15:50:50 +00:00
output: {
keep_quoted_props: true,
},
});
assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};');
});
it("Should preserve quote styles when quote_style is 3", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(js, {
unify CLI & API under `minify()` (#1811) - rename `screw_ie8` to `ie8` - rename `mangle.except` to `mangle.reserved` - rename `mangle.properties.ignore_quoted` to `mangle.properties.keep_quoted` - compact `sourceMap` options - more stringent verification on input `options` - toplevel shorthands - `ie8` - `keep_fnames` - `toplevel` - `warnings` - support arrays and unquoted string values on CLI - drop `fromString` from `minify()` - `minify()` no longer handles any `fs` operations - unify order of operations for `mangle_properties()` on CLI & API - `bin/uglifyjs` used to `mangle_properties()` before even `Compressor` - `minify()` used to `mangle_properties()` after `Compressor` but before `mangle_names()` - both will now do `Compressor`, `mangle_names()` then `mangle_properties()` - `options.parse` / `--parse` for parser options beyond `bare_returns` - add `mangle.properties.builtins` to disable built-in reserved list - disable with `--mangle-props builtins` on CLI - `warnings` now off by default - add `--warn` and `--verbose` on CLI - drop `--enclose` - drop `--export-all` - drop `--reserved-file` - use `--mangle reserved` instead - drop `--reserve-domprops` - enabled by default, disable with `--mangle-props domprops` - drop `--prefix` - use `--source-map base` instead - drop `--lint` - remove `bin/extract-props.js` - limit exposure of internal APIs - update documentations closes #96 closes #102 closes #136 closes #166 closes #243 closes #254 closes #261 closes #311 closes #700 closes #748 closes #912 closes #1072 closes #1366 fixes #101 fixes #123 fixes #124 fixes #263 fixes #379 fixes #419 fixes #423 fixes #461 fixes #465 fixes #576 fixes #737 fixes #772 fixes #958 fixes #1036 fixes #1142 fixes #1175 fixes #1220 fixes #1223 fixes #1280 fixes #1359 fixes #1368
2017-04-15 15:50:50 +00:00
output: {
keep_quoted_props: true,
quote_style: 3,
},
});
assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};');
});
it("Should not preserve quotes in object literals when disabled", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(js, {
unify CLI & API under `minify()` (#1811) - rename `screw_ie8` to `ie8` - rename `mangle.except` to `mangle.reserved` - rename `mangle.properties.ignore_quoted` to `mangle.properties.keep_quoted` - compact `sourceMap` options - more stringent verification on input `options` - toplevel shorthands - `ie8` - `keep_fnames` - `toplevel` - `warnings` - support arrays and unquoted string values on CLI - drop `fromString` from `minify()` - `minify()` no longer handles any `fs` operations - unify order of operations for `mangle_properties()` on CLI & API - `bin/uglifyjs` used to `mangle_properties()` before even `Compressor` - `minify()` used to `mangle_properties()` after `Compressor` but before `mangle_names()` - both will now do `Compressor`, `mangle_names()` then `mangle_properties()` - `options.parse` / `--parse` for parser options beyond `bare_returns` - add `mangle.properties.builtins` to disable built-in reserved list - disable with `--mangle-props builtins` on CLI - `warnings` now off by default - add `--warn` and `--verbose` on CLI - drop `--enclose` - drop `--export-all` - drop `--reserved-file` - use `--mangle reserved` instead - drop `--reserve-domprops` - enabled by default, disable with `--mangle-props domprops` - drop `--prefix` - use `--source-map base` instead - drop `--lint` - remove `bin/extract-props.js` - limit exposure of internal APIs - update documentations closes #96 closes #102 closes #136 closes #166 closes #243 closes #254 closes #261 closes #311 closes #700 closes #748 closes #912 closes #1072 closes #1366 fixes #101 fixes #123 fixes #124 fixes #263 fixes #379 fixes #419 fixes #423 fixes #461 fixes #465 fixes #576 fixes #737 fixes #772 fixes #958 fixes #1036 fixes #1142 fixes #1175 fixes #1220 fixes #1223 fixes #1280 fixes #1359 fixes #1368
2017-04-15 15:50:50 +00:00
output: {
keep_quoted_props: false,
quote_style: 3,
},
});
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
});
});
describe("mangleProperties", function() {
it("Shouldn't mangle quoted properties", function() {
var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};';
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(js, {
compress: true,
unify CLI & API under `minify()` (#1811) - rename `screw_ie8` to `ie8` - rename `mangle.except` to `mangle.reserved` - rename `mangle.properties.ignore_quoted` to `mangle.properties.keep_quoted` - compact `sourceMap` options - more stringent verification on input `options` - toplevel shorthands - `ie8` - `keep_fnames` - `toplevel` - `warnings` - support arrays and unquoted string values on CLI - drop `fromString` from `minify()` - `minify()` no longer handles any `fs` operations - unify order of operations for `mangle_properties()` on CLI & API - `bin/uglifyjs` used to `mangle_properties()` before even `Compressor` - `minify()` used to `mangle_properties()` after `Compressor` but before `mangle_names()` - both will now do `Compressor`, `mangle_names()` then `mangle_properties()` - `options.parse` / `--parse` for parser options beyond `bare_returns` - add `mangle.properties.builtins` to disable built-in reserved list - disable with `--mangle-props builtins` on CLI - `warnings` now off by default - add `--warn` and `--verbose` on CLI - drop `--enclose` - drop `--export-all` - drop `--reserved-file` - use `--mangle reserved` instead - drop `--reserve-domprops` - enabled by default, disable with `--mangle-props domprops` - drop `--prefix` - use `--source-map base` instead - drop `--lint` - remove `bin/extract-props.js` - limit exposure of internal APIs - update documentations closes #96 closes #102 closes #136 closes #166 closes #243 closes #254 closes #261 closes #311 closes #700 closes #748 closes #912 closes #1072 closes #1366 fixes #101 fixes #123 fixes #124 fixes #263 fixes #379 fixes #419 fixes #423 fixes #461 fixes #465 fixes #576 fixes #737 fixes #772 fixes #958 fixes #1036 fixes #1142 fixes #1175 fixes #1220 fixes #1223 fixes #1280 fixes #1359 fixes #1368
2017-04-15 15:50:50 +00:00
mangle: {
properties: {
domprops: true,
keep_quoted: true,
},
},
output: {
keep_quoted_props: true,
quote_style: 3,
},
});
assert.strictEqual(result.code, 'a["foo"]="bar",a.a="red",x={"bar":10};');
});
it("Should not mangle quoted property within dead code", function() {
var result = UglifyJS.minify('({ "keep": 1 }); g.keep = g.change = 42;', {
mangle: {
properties: {
keep_quoted: true,
},
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "g.keep=g.g=42;");
});
});
2016-07-27 14:02:33 +00:00
describe("#__PURE__", function() {
it("Should drop #__PURE__ hint after use", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', {
output: {
comments: "all",
beautify: false,
},
});
var code = result.code;
assert.strictEqual(code, "// comment1 comment2\nbar();");
});
it("Should drop #__PURE__ hint if function is retained", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify("var a = /*#__PURE__*/(function(){ foo(); })();", {
output: {
comments: "all",
beautify: false,
},
});
var code = result.code;
2021-03-12 19:40:49 +00:00
assert.strictEqual(code, "var a=function(){foo()}();");
});
});
describe("JS_Parse_Error", function() {
it("Should return syntax error", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify("function f(a{}");
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: punc «{», expected: punc «,»");
assert.strictEqual(err.filename, "0");
assert.strictEqual(err.line, 1);
assert.strictEqual(err.col, 12);
});
it("Should reject duplicated label name", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify("L:{L:{}}");
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Label L defined twice");
assert.strictEqual(err.filename, "0");
assert.strictEqual(err.line, 1);
assert.strictEqual(err.col, 4);
});
});
describe("global_defs", function() {
it("Should throw for non-trivial expressions", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify("alert(42);", {
compress: {
global_defs: {
"@alert": "debugger"
}
}
});
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: keyword «debugger»");
});
it("Should skip inherited properties", function() {
var foo = Object.create({ skip: this });
foo.bar = 42;
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify("alert(FOO);", {
compress: {
global_defs: {
FOO: foo
}
}
});
assert.strictEqual(result.code, "alert({bar:42});");
});
});
describe("collapse_vars", function() {
it("Should not produce invalid AST", function() {
var code = [
"function f(a) {",
" a = x();",
" return a;",
"}",
"f();",
].join("\n");
2018-06-21 17:04:15 +00:00
var ast = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ast: true,
},
}).ast;
assert.strictEqual(ast.TYPE, "Toplevel");
assert.strictEqual(ast.body.length, 2);
assert.strictEqual(ast.body[0].TYPE, "Defun");
assert.strictEqual(ast.body[0].body.length, 2);
assert.strictEqual(ast.body[0].body[0].TYPE, "SimpleStatement");
var stat = ast.body[0].body[0];
2018-06-21 17:04:15 +00:00
UglifyJS.minify(ast, {
compress: {
sequences: false,
},
mangle: false,
});
assert.ok(stat.body);
assert.strictEqual(stat.print_to_string(), "a=x()");
});
});
describe("module", function() {
it("Should not inline `await` variables", function() {
if (semver.satisfies(process.version, "<8")) return;
var code = [
"console.log(function() {",
" return typeof await;",
"}());",
].join("\n");
assert.strictEqual(run_code("(async function(){" + code + "})();"), "undefined\n");
var result = UglifyJS.minify(code, {
module: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "console.log(function(){return typeof await}());");
assert.strictEqual(run_code("(async function(){" + result.code + "})();"), "undefined\n");
});
});
describe("rename", function() {
it("Should be repeatable", function() {
var code = "!function(x){return x(x)}(y);";
for (var i = 0; i < 2; i++) {
2018-06-21 17:04:15 +00:00
assert.strictEqual(UglifyJS.minify(code, {
compress: {
toplevel: true,
},
rename: true,
}).code, "var a;(a=y)(a);");
}
});
});
describe("enclose", function() {
var code = read("test/input/enclose/input.js");
it("Should work with true", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
compress: false,
enclose: true,
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(){function enclose(){console.log("test enclose")}enclose()})();');
});
it("Should work with arg", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
compress: false,
enclose: 'undefined',
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();');
});
it("Should work with arg:value", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
compress: false,
enclose: 'window,undefined:window',
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);');
});
it("Should work alongside wrap", function() {
2018-06-21 17:04:15 +00:00
var result = UglifyJS.minify(code, {
compress: false,
enclose: 'window,undefined:window',
mangle: false,
wrap: 'exports',
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(exports){(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window)})(typeof exports=="undefined"?exports={}:exports);');
});
});
});