Add option to preserve/enforce string quote style
`-q 0` (default) use single or double quotes such as to minimize the number of bytes (prefers double quotes when both will do); this is the previous behavior. `-q 1` -- always use single quotes `-q 2` -- always use double quotes `-q 3` or just `-q` -- always use the original quotes. Related codegen option: `quote_style`. Close #495 Close #460 Some `yargs` guru please tell me why `uglifyjs --help` doesn't display the help string for `-q` / `--quotes`, and why it doesn't output the expected argument types anymore, like good old `optimist` did.
This commit is contained in:
15
lib/ast.js
15
lib/ast.js
@@ -120,11 +120,12 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
||||
$documentation: "Represents a debugger statement",
|
||||
}, AST_Statement);
|
||||
|
||||
var AST_Directive = DEFNODE("Directive", "value scope", {
|
||||
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
||||
$documentation: "Represents a directive, like \"use strict\";",
|
||||
$propdoc: {
|
||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||
scope: "[AST_Scope/S] The scope that this directive affects"
|
||||
scope: "[AST_Scope/S] The scope that this directive affects",
|
||||
quote: "[string] the original quote character"
|
||||
},
|
||||
}, AST_Statement);
|
||||
|
||||
@@ -766,8 +767,11 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||
}
|
||||
});
|
||||
|
||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
|
||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||
$documentation: "A key: value object property",
|
||||
$propdoc: {
|
||||
quote: "[string] the original quote character"
|
||||
}
|
||||
}, AST_ObjectProperty);
|
||||
|
||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
@@ -852,10 +856,11 @@ var AST_Constant = DEFNODE("Constant", null, {
|
||||
}
|
||||
});
|
||||
|
||||
var AST_String = DEFNODE("String", "value", {
|
||||
var AST_String = DEFNODE("String", "value quote", {
|
||||
$documentation: "A string literal",
|
||||
$propdoc: {
|
||||
value: "[string] the contents of this string"
|
||||
value: "[string] the contents of this string",
|
||||
quote: "[string] the original quote character"
|
||||
}
|
||||
}, AST_Constant);
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ function OutputStream(options) {
|
||||
preserve_line : false,
|
||||
screw_ie8 : false,
|
||||
preamble : null,
|
||||
quote_style : 0
|
||||
}, true);
|
||||
|
||||
var indentation = 0;
|
||||
@@ -84,7 +85,7 @@ function OutputStream(options) {
|
||||
});
|
||||
};
|
||||
|
||||
function make_string(str) {
|
||||
function make_string(str, quote) {
|
||||
var dq = 0, sq = 0;
|
||||
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s){
|
||||
switch (s) {
|
||||
@@ -102,13 +103,27 @@ function OutputStream(options) {
|
||||
}
|
||||
return s;
|
||||
});
|
||||
function quote_single() {
|
||||
return "'" + str.replace(/\x27/g, "\\'") + "'";
|
||||
}
|
||||
function quote_double() {
|
||||
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||
}
|
||||
if (options.ascii_only) str = to_ascii(str);
|
||||
if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
|
||||
else return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||
switch (options.quote_style) {
|
||||
case 1:
|
||||
return quote_single();
|
||||
case 2:
|
||||
return quote_double();
|
||||
case 3:
|
||||
return quote == "'" ? quote_single() : quote_double();
|
||||
default:
|
||||
return dq > sq ? quote_single() : quote_double();
|
||||
}
|
||||
};
|
||||
|
||||
function encode_string(str) {
|
||||
var ret = make_string(str);
|
||||
function encode_string(str, quote) {
|
||||
var ret = make_string(str, quote);
|
||||
if (options.inline_script)
|
||||
ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
|
||||
return ret;
|
||||
@@ -324,7 +339,7 @@ function OutputStream(options) {
|
||||
force_semicolon : force_semicolon,
|
||||
to_ascii : to_ascii,
|
||||
print_name : function(name) { print(make_name(name)) },
|
||||
print_string : function(str) { print(encode_string(str)) },
|
||||
print_string : function(str, quote) { print(encode_string(str, quote)) },
|
||||
next_indent : next_indent,
|
||||
with_indent : with_indent,
|
||||
with_block : with_block,
|
||||
@@ -581,7 +596,7 @@ function OutputStream(options) {
|
||||
/* -----[ PRINTERS ]----- */
|
||||
|
||||
DEFPRINT(AST_Directive, function(self, output){
|
||||
output.print_string(self.value);
|
||||
output.print_string(self.value, self.quote);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Debugger, function(self, output){
|
||||
@@ -1077,6 +1092,7 @@ function OutputStream(options) {
|
||||
});
|
||||
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
||||
var key = self.key;
|
||||
var quote = self.quote;
|
||||
if (output.option("quote_keys")) {
|
||||
output.print_string(key + "");
|
||||
} else if ((typeof key == "number"
|
||||
@@ -1087,7 +1103,7 @@ function OutputStream(options) {
|
||||
} else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
|
||||
output.print_name(key);
|
||||
} else {
|
||||
output.print_string(key);
|
||||
output.print_string(key, quote);
|
||||
}
|
||||
output.colon();
|
||||
self.value.print(output);
|
||||
@@ -1125,7 +1141,7 @@ function OutputStream(options) {
|
||||
output.print(self.getValue());
|
||||
});
|
||||
DEFPRINT(AST_String, function(self, output){
|
||||
output.print_string(self.getValue());
|
||||
output.print_string(self.getValue(), self.quote);
|
||||
});
|
||||
DEFPRINT(AST_Number, function(self, output){
|
||||
output.print(make_num(self.getValue()));
|
||||
|
||||
26
lib/parse.js
26
lib/parse.js
@@ -367,7 +367,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||
return num;
|
||||
};
|
||||
|
||||
var read_string = with_eof_error("Unterminated string constant", function(){
|
||||
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
||||
var quote = next(), ret = "";
|
||||
for (;;) {
|
||||
var ch = next(true);
|
||||
@@ -392,7 +392,9 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||
else if (ch == quote) break;
|
||||
ret += ch;
|
||||
}
|
||||
return token("string", ret);
|
||||
var tok = token("string", ret);
|
||||
tok.quote = quote_char;
|
||||
return tok;
|
||||
});
|
||||
|
||||
function skip_line_comment(type) {
|
||||
@@ -547,7 +549,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
||||
if (!ch) return token("eof");
|
||||
var code = ch.charCodeAt(0);
|
||||
switch (code) {
|
||||
case 34: case 39: return read_string();
|
||||
case 34: case 39: return read_string(ch);
|
||||
case 46: return handle_dot();
|
||||
case 47: return handle_slash();
|
||||
}
|
||||
@@ -737,8 +739,14 @@ function parse($TEXT, options) {
|
||||
case "string":
|
||||
var dir = S.in_directives, stat = simple_statement();
|
||||
// XXXv2: decide how to fix directives
|
||||
if (dir && stat.body instanceof AST_String && !is("punc", ","))
|
||||
return new AST_Directive({ value: stat.body.value });
|
||||
if (dir && stat.body instanceof AST_String && !is("punc", ",")) {
|
||||
return new AST_Directive({
|
||||
start : stat.body.start,
|
||||
end : stat.body.end,
|
||||
quote : stat.body.quote,
|
||||
value : stat.body.value,
|
||||
});
|
||||
}
|
||||
return stat;
|
||||
case "num":
|
||||
case "regexp":
|
||||
@@ -1124,7 +1132,12 @@ function parse($TEXT, options) {
|
||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||
break;
|
||||
case "string":
|
||||
ret = new AST_String({ start: tok, end: tok, value: tok.value });
|
||||
ret = new AST_String({
|
||||
start : tok,
|
||||
end : tok,
|
||||
value : tok.value,
|
||||
quote : tok.quote
|
||||
});
|
||||
break;
|
||||
case "regexp":
|
||||
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
|
||||
@@ -1237,6 +1250,7 @@ function parse($TEXT, options) {
|
||||
expect(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start : start,
|
||||
quote : start.quote,
|
||||
key : name,
|
||||
value : expression(false),
|
||||
end : prev()
|
||||
|
||||
Reference in New Issue
Block a user