Repository: mishoo/UglifyJS (JavaScript)

Issue:
keep_quoted_props
<!-- Note: sub-optimal but correct code is not a bug -->

**Uglify version (`uglifyjs -V`)**
uglify-js 3.13.10
**JavaScript input**

<!--
A complete parsable JS program exhibiting the issue with UglifyJS alone
- without third party tools or libraries.

Ideally the input should be as small as possible, but may be large if isolating
the problem proves to be difficult. The most important thing is that the
standalone program reliably exhibits the bug when minified. Provide a link to a
gist if necessary.

Solely providing minified output without the original uglify JS input is not
useful in determining the cause of the problem. Issues without a reproducible
test case will be closed.
-->

**The `uglifyjs` CLI command executed or `minify()` options used.**

<!--
Command-line or API call to UglifyJS without third party tools or libraries.
For users using bundlers or transpilers, you may be able to gather the required
information through setting the `UGLIFY_BUG_REPORT` environment variable:

    export UGLIFY_BUG_REPORT=1      (bash)
    set UGLIFY_BUG_REPORT=1         (Command Prompt)
    $Env:UGLIFY_BUG_REPORT=1        (PowerShell)

before running your usual build process. The resulting "minified" output should
contain the necessary details for this report.
-->
Command line 1: using a config file
uglifyjs inputFile --config-file Minify/minifyConfig.json --output outputFile
minifyConfig
{
  "output": {
    "keep_quoted_props": true
  }
}

Command line 2: 
uglifyjs inputFile -p bare_returns=true -O keep_quoted_props=true --output outputFile

**JavaScript output or error produced.**

<!--
Only minified code that produces different output (or error) from the original
upon execution would be considered a bug.
-->
Error: double quotes around keys such as {"1000": ["Jack", "Jim", "Dan"]} are stripped.

Reading the description of keep_quoted_props I thought the quotes would be retained if set to true:
keep_quoted_props (default: false) — when turned on, prevents stripping quotes from property names in object literals.

Thank you.


Discussion:
Seems to be a special case for numeric keys:
```js
$ cat input.js
console.log({
    'a': [],
    "42": {},
});
```
```js
$ uglifyjs input.js -O keep_quoted_props
console.log({"a":[],42:{}});
```
And it's been like that [since this feature existed](https://github.com/mishoo/UglifyJS/commit/e645ba84cfc950183a222c2cce2ea6b94fe51226) &minus; none of the test cases contain numeric keys though, so this may be an oversight.
Patch released in `uglify-js@3.14.0`



Patch:
diff --git a/lib/output.js b/lib/output.js
index afc89055c81..0cf379dd287 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -1690,28 +1690,21 @@ function OutputStream(options) {
 
     function print_property_key(self, output) {
         var key = self.key;
-        if (key instanceof AST_Node) {
-            output.with_square(function() {
-                key.print(output);
-            });
-        } else if (output.option("quote_keys")) {
-            output.print_string(key);
+        if (key instanceof AST_Node) return output.with_square(function() {
+            key.print(output);
+        });
+        var quote = self.start && self.start.quote;
+        if (output.option("quote_keys") || quote && output.option("keep_quoted_props")) {
+            output.print_string(key, quote);
         } else if ("" + +key == key && key >= 0) {
             output.print(make_num(key));
+        } else if (self.private) {
+            output.print_name(key);
+        } else if (RESERVED_WORDS[key] ? !output.option("ie") : is_identifier_string(key)) {
+            output.print_name(key);
+            return key;
         } else {
-            var quote = self.start && self.start.quote;
-            if (self.private) {
-                output.print_name(key);
-            } else if (RESERVED_WORDS[key] ? !output.option("ie") : is_identifier_string(key)) {
-                if (quote && output.option("keep_quoted_props")) {
-                    output.print_string(key, quote);
-                } else {
-                    output.print_name(key);
-                    return key;
-                }
-            } else {
-                output.print_string(key, quote);
-            }
+            output.print_string(key, quote);
         }
     }
     DEFPRINT(AST_ObjectKeyVal, function(output) {


Test patch:
diff --git a/test/compress/properties.js b/test/compress/properties.js
index 929c444e9c6..fb0db99e7c4 100644
--- a/test/compress/properties.js
+++ b/test/compress/properties.js
@@ -1463,3 +1463,50 @@ issue_4888: {
     }
     expect_stdout: "object"
 }
+
+issue_5093: {
+    beautify = {
+        keep_quoted_props: true,
+    }
+    input: {
+        console.log({
+            a: true,
+            '42': "PASS",
+            "null": [],
+        }[6 * 7]);
+    }
+    expect_exact: 'console.log({a:true,"42":"PASS","null":[]}[6*7]);'
+    expect_stdout: "PASS"
+}
+
+issue_5093_quote_keys: {
+    beautify = {
+        keep_quoted_props: true,
+        quote_keys: true,
+    }
+    input: {
+        console.log({
+            a: true,
+            '42': "PASS",
+            "null": [],
+        }[6 * 7]);
+    }
+    expect_exact: 'console.log({"a":true,"42":"PASS","null":[]}[6*7]);'
+    expect_stdout: "PASS"
+}
+
+issue_5093_quote_style: {
+    beautify = {
+        keep_quoted_props: true,
+        quote_style: 3,
+    }
+    input: {
+        console.log({
+            a: true,
+            '42': "PASS",
+            "null": [],
+        }[6 * 7]);
+    }
+    expect_exact: 'console.log({a:true,\'42\':"PASS","null":[]}[6*7]);'
+    expect_stdout: "PASS"
+}