From 80ebacbf51ccf449d47f5ce5a41fffeae4f9c454 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L." Date: Thu, 8 Aug 2024 02:21:27 +0300 Subject: [PATCH] generate shorter unicode escape sequence (#5914) - fix input option mutation --- bin/uglifyjs | 9 +++-- lib/minify.js | 7 ++-- lib/output.js | 17 +++++++-- test/compress/templates.js | 72 ++++++++++++++++++++++++++++++++++++++ test/compress/unicode.js | 37 ++++++++++++++++++++ test/mocha/minify.js | 5 ++- tools/node.js | 7 +++- 7 files changed, 143 insertions(+), 11 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index 4b790f4bfb4..a99dbe9a2cd 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -467,11 +467,14 @@ function run() { } else if (output) { var code; if (result.ast) { - var opts = {}; + var output_options = {}; + for (var name in UglifyJS.default_options("output")) { + if (name in options) output_options[name] = options[name]; + } for (var name in options.output) { - if (!/^ast|code$/.test(name)) opts[name] = options.output[name]; + if (!/^ast|code$/.test(name)) output_options[name] = options.output[name]; } - code = UglifyJS.AST_Node.from_mozilla_ast(result.ast.to_mozilla_ast()).print_to_string(opts); + code = UglifyJS.AST_Node.from_mozilla_ast(result.ast.to_mozilla_ast()).print_to_string(output_options); } else { code = result.code; } diff --git a/lib/minify.js b/lib/minify.js index 1771338c1ff..66d0bd324a1 100644 --- a/lib/minify.js +++ b/lib/minify.js @@ -49,8 +49,9 @@ function parse_source_map(content) { function set_shorthand(name, options, keys) { keys.forEach(function(key) { if (options[key]) { - if (typeof options[key] != "object") options[key] = {}; - if (!(name in options[key])) options[key][name] = options[name]; + var defs = {}; + defs[name] = options[name]; + options[key] = defaults(options[key], defs); } }); } @@ -105,7 +106,7 @@ function minify(files, options) { if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]); if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]); if (options.module === undefined && !options.ie) options.module = true; - if (options.module) set_shorthand("module", options, [ "compress", "parse" ]); + if (options.module) set_shorthand("module", options, [ "compress", "output", "parse" ]); if (options.toplevel !== undefined) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]); if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]); if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]); diff --git a/lib/output.js b/lib/output.js index 2982cc3f604..ac275445eb8 100644 --- a/lib/output.js +++ b/lib/output.js @@ -63,6 +63,7 @@ function OutputStream(options) { inline_script : true, keep_quoted_props: false, max_line_len : false, + module : false, preamble : null, preserve_line : false, quote_keys : false, @@ -140,12 +141,22 @@ function OutputStream(options) { reset(); var to_utf8 = options.ascii_only ? function(str, identifier) { - if (identifier) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) { + if (identifier || options.module) str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) { return "\\u{" + (ch.charCodeAt(0) - 0xd7c0 << 10 | ch.charCodeAt(1) - 0xdc00).toString(16) + "}"; }); - return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); + return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(s, i) { + var code = s.charCodeAt(0).toString(16); if (code.length <= 2 && !identifier) { + switch (s) { + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\x0B": return options.ie ? "\\x0B" : "\\v"; + case "\0": + return /[0-9]/.test(str.charAt(i+1)) ? "\\x00" : "\\0"; + } while (code.length < 2) code = "0" + code; return "\\x" + code; } else { diff --git a/test/compress/templates.js b/test/compress/templates.js index 604f9dedf59..a03f7658c22 100644 --- a/test/compress/templates.js +++ b/test/compress/templates.js @@ -432,6 +432,7 @@ pure_funcs: { ascii_only: { beautify = { ascii_only: true, + module: false, } options = { templates: false, @@ -445,9 +446,27 @@ ascii_only: { node_version: ">=6" } +ascii_only_ecma: { + beautify = { + ascii_only: true, + module: true, + } + options = { + templates: false, + } + input: { + console.log(`\ud801\udc37\ud801𐐷${42}\u{10437}`); + } + expect_exact: "console.log(`\\ud801\\udc37\\ud801\\u{10437}${42}\\u{10437}`);" + expect_stdout: "𐐷\ud801𐐷42𐐷" + // non-BMP support is platform-dependent on Node.js v4 + node_version: ">=6" +} + ascii_only_templates: { beautify = { ascii_only: true, + module: false, } options = { templates: true, @@ -461,9 +480,44 @@ ascii_only_templates: { node_version: ">=6" } +ascii_only_templates_ecma: { + beautify = { + ascii_only: true, + module: true, + } + options = { + templates: true, + } + input: { + console.log(`\ud801\udc37\ud801𐐷${42}\u{10437}`); + } + expect_exact: "console.log(`\\u{10437}\\ud801\\u{10437}${42}\\u{10437}`);" + expect_stdout: "𐐷\ud801𐐷42𐐷" + // non-BMP support is platform-dependent on Node.js v4 + node_version: ">=6" +} + unicode: { beautify = { ascii_only: false, + module: false, + } + options = { + templates: false, + } + input: { + console.log(`\ud801\udc37\ud801𐐷${42}\u{10437}`); + } + expect_exact: "console.log(`\\ud801\\udc37\\ud801𐐷${42}\\u{10437}`);" + expect_stdout: "𐐷\ud801𐐷42𐐷" + // non-BMP support is platform-dependent on Node.js v4 + node_version: ">=6" +} + +unicode_ecma: { + beautify = { + ascii_only: false, + module: true, } options = { templates: false, @@ -480,6 +534,24 @@ unicode: { unicode_templates: { beautify = { ascii_only: false, + module: false, + } + options = { + templates: true, + } + input: { + console.log(`\ud801\udc37\ud801𐐷${42}\u{10437}`); + } + expect_exact: "console.log(`𐐷\\ud801𐐷${42}𐐷`);" + expect_stdout: "𐐷\ud801𐐷42𐐷" + // non-BMP support is platform-dependent on Node.js v4 + node_version: ">=6" +} + +unicode_templates_ecma: { + beautify = { + ascii_only: false, + module: true, } options = { templates: true, diff --git a/test/compress/unicode.js b/test/compress/unicode.js index abbd417df5b..aa9da7be698 100644 --- a/test/compress/unicode.js +++ b/test/compress/unicode.js @@ -191,6 +191,24 @@ issue_2569: { surrogate_pair: { beautify = { ascii_only: false, + module: false, + } + input: { + var \u{2f800} = { + \u{2f801}: "\u{100000}", + }; + \u{2f800}.\u{2f802} = "\u{100001}"; + console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]); + } + expect_exact: 'var \ud87e\udc00={"\ud87e\udc01":"\udbc0\udc00"};\ud87e\udc00.\ud87e\udc02="\udbc0\udc01";console.log(typeof \ud87e\udc00,\ud87e\udc00.\ud87e\udc01,\ud87e\udc00["\ud87e\udc02"]);' + expect_stdout: "object \udbc0\udc00 \udbc0\udc01" + // non-BMP support is platform-dependent on Node.js v4 + node_version: ">=6" +} +surrogate_pair_ecma: { + beautify = { + ascii_only: false, + module: true, } input: { var \u{2f800} = { @@ -208,6 +226,7 @@ surrogate_pair: { surrogate_pair_ascii: { beautify = { ascii_only: true, + module: false, } input: { var \u{2f800} = { @@ -221,3 +240,21 @@ surrogate_pair_ascii: { // non-BMP support is platform-dependent on Node.js v4 node_version: ">=6" } + +surrogate_pair_ascii_ecma: { + beautify = { + ascii_only: true, + module: true, + } + input: { + var \u{2f800} = { + \u{2f801}: "\u{100000}", + }; + \u{2f800}.\u{2f802} = "\u{100001}"; + console.log(typeof \u{2f800}, \u{2f800}.\u{2f801}, \u{2f800}["\u{2f802}"]); + } + expect_exact: 'var \\u{2f800}={"\\u{2f801}":"\\u{100000}"};\\u{2f800}.\\u{2f802}="\\u{100001}";console.log(typeof \\u{2f800},\\u{2f800}.\\u{2f801},\\u{2f800}["\\u{2f802}"]);' + expect_stdout: "object \udbc0\udc00 \udbc0\udc01" + // non-BMP support is platform-dependent on Node.js v4 + node_version: ">=6" +} diff --git a/test/mocha/minify.js b/test/mocha/minify.js index a9ef993980e..0b3bb874937 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -19,7 +19,10 @@ describe("minify", function() { var options = { compress: true, mangle: false, - output: {}, + output: { + v8: false, + }, + webkit: true, }; var value = JSON.stringify(options); var result = UglifyJS.minify("print(6 * 7);", options); diff --git a/tools/node.js b/tools/node.js index 9e7960b1e2d..59cdb44e3f2 100644 --- a/tools/node.js +++ b/tools/node.js @@ -97,7 +97,12 @@ function infer_options(options) { return result.error && result.error.defs; } -exports.default_options = function() { +exports.default_options = function(component) { + if (component) { + var options = { module: false }; + options[component] = { 0: 0 }; + return infer_options(options); + } var defs = infer_options({ 0: 0 }); Object.keys(defs).forEach(function(component) { var options = { module: false };