[Pkg-javascript-commits] [uglifyjs] 45/77: Add option to preserve/enforce string quote style

Jonas Smedegaard dr at jones.dk
Tue May 19 00:02:31 UTC 2015


This is an automated email from the git hooks/post-receive script.

js pushed a commit to tag v2.4.18
in repository uglifyjs.

commit fbbaa42ee55a7f753f7cab9b1a905ccf73cf26d5
Author: Mihai Bazon <mihai.bazon at gmail.com>
Date:   Tue Jan 27 22:26:27 2015 +0200

    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.
---
 README.md     |  7 +++++++
 bin/uglifyjs  | 11 +++++++++--
 lib/ast.js    | 15 ++++++++++-----
 lib/output.js | 34 +++++++++++++++++++++++++---------
 lib/parse.js  | 26 ++++++++++++++++++++------
 5 files changed, 71 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index d2ec432..2bb2138 100644
--- a/README.md
+++ b/README.md
@@ -352,6 +352,13 @@ can pass additional arguments that control the code output:
   it will be prepended to the output literally.  The source map will
   adjust for this text.  Can be used to insert a comment containing
   licensing information, for example.
+- `quote_style` (default `0`) -- preferred quote style for strings (affects
+  quoted property names and directives as well):
+  - `0` -- prefers double quotes, switches to single quotes when there are
+    more double quotes in the string itself.
+  - `1` -- always use single quotes
+  - `2` -- always use double quotes
+  - `3` -- always use the original quotes
 
 ### Keeping copyright notices or other comments
 
diff --git a/bin/uglifyjs b/bin/uglifyjs
index 11c3a01..c9f4c12 100755
--- a/bin/uglifyjs
+++ b/bin/uglifyjs
@@ -66,6 +66,7 @@ You need to pass an argument to this option to specify the name that your module
     .describe("noerr", "Don't throw an error for unknown options in -c, -b or -m.")
     .describe("bare-returns", "Allow return outside of functions.  Useful when minifying CommonJS modules.")
     .describe("keep-fnames", "Do not mangle/drop function names.  Useful for code relying on Function.prototype.name.")
+    .describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
 
     .alias("p", "prefix")
     .alias("o", "output")
@@ -77,6 +78,7 @@ You need to pass an argument to this option to specify the name that your module
     .alias("r", "reserved")
     .alias("V", "version")
     .alias("e", "enclose")
+    .alias("q", "quotes")
 
     .string("source-map")
     .string("source-map-root")
@@ -151,9 +153,14 @@ if (ARGS.r) {
     if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
 }
 
+if (ARGS.quotes === true) {
+    ARGS.quotes = 3;
+}
+
 var OUTPUT_OPTIONS = {
-    beautify: BEAUTIFY ? true : false,
-    preamble: ARGS.preamble || null,
+    beautify    : BEAUTIFY ? true : false,
+    preamble    : ARGS.preamble || null,
+    quote_style : ARGS.quotes != null ? ARGS.quotes : 0
 };
 
 if (ARGS.screw_ie8) {
diff --git a/lib/ast.js b/lib/ast.js
index 5aa1be3..2e539cf 100644
--- a/lib/ast.js
+++ b/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);
 
diff --git a/lib/output.js b/lib/output.js
index bfe6242..135636b 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -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()));
diff --git a/lib/parse.js b/lib/parse.js
index 35ce7ef..78c1dd4 100644
--- a/lib/parse.js
+++ b/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()

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git



More information about the Pkg-javascript-commits mailing list