Skip to content

Commit

Permalink
generate shorter unicode escape sequence (mishoo#5914)
Browse files Browse the repository at this point in the history
- fix input option mutation
  • Loading branch information
alexlamsl authored Aug 7, 2024
1 parent 69f4e3a commit 80ebacb
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 11 deletions.
9 changes: 6 additions & 3 deletions bin/uglifyjs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/minify.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
}
Expand Down Expand Up @@ -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" ]);
Expand Down
17 changes: 14 additions & 3 deletions lib/output.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
72 changes: 72 additions & 0 deletions test/compress/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ pure_funcs: {
ascii_only: {
beautify = {
ascii_only: true,
module: false,
}
options = {
templates: false,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
37 changes: 37 additions & 0 deletions test/compress/unicode.js
Original file line number Diff line number Diff line change
Expand Up @@ -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} = {
Expand All @@ -208,6 +226,7 @@ surrogate_pair: {
surrogate_pair_ascii: {
beautify = {
ascii_only: true,
module: false,
}
input: {
var \u{2f800} = {
Expand All @@ -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"
}
5 changes: 4 additions & 1 deletion test/mocha/minify.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion tools/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down

0 comments on commit 80ebacb

Please sign in to comment.