From c4af355521e927b6f350db0cdaa5320e08f0c31e Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Sun, 18 Feb 2024 17:59:06 +0800 Subject: [PATCH] Fix `isStringKeySafeToUnquote` (#16058) --- changelog_unreleased/javascript/16058.md | 16 ++ src/language-js/print/property.js | 3 +- .../__snapshots__/jsfmt.spec.js.snap | 152 +++++++++++------- tests/format/js/quote-props/jsfmt.spec.js | 21 +-- tests/format/js/quote-props/objects.js | 19 ++- 5 files changed, 128 insertions(+), 83 deletions(-) create mode 100644 changelog_unreleased/javascript/16058.md diff --git a/changelog_unreleased/javascript/16058.md b/changelog_unreleased/javascript/16058.md new file mode 100644 index 000000000000..f870d51b783d --- /dev/null +++ b/changelog_unreleased/javascript/16058.md @@ -0,0 +1,16 @@ +#### Fix unstable object print (#16058 by @fisker) + + +```jsx +// Input +a = {"\a": 1, "b": 2} + +// Prettier stable (--quote-props consistent) +a = { "a": 1, "b": 2 }; + +// Prettier stable (--quote-props as-needed) +a = { "a": 1, b: 2 }; + +// Prettier main +a = { a: 1, b: 2 }; +``` diff --git a/src/language-js/print/property.js b/src/language-js/print/property.js index 569a40206c58..c62ad0a56a91 100644 --- a/src/language-js/print/property.js +++ b/src/language-js/print/property.js @@ -44,8 +44,7 @@ function isStringKeySafeToUnquote(node, options) { options.parser === "json" || options.parser === "jsonc" || !isStringLiteral(node.key) || - // TODO[@fisker]: Use `printString` instead - rawText(node.key).slice(1, -1) !== node.key.value + printString(rawText(node.key), options).slice(1, -1) !== node.key.value ) { return false; } diff --git a/tests/format/js/quote-props/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/quote-props/__snapshots__/jsfmt.spec.js.snap index 607faf8b47ce..2c612aa6d1c5 100644 --- a/tests/format/js/quote-props/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/js/quote-props/__snapshots__/jsfmt.spec.js.snap @@ -293,32 +293,32 @@ printWidth: 80 quoteProps: "as-needed" | printWidth =====================================input====================================== -const a = { +a = { a: "a" }; -const b = { +a = { 'b': "b" }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. '\\u0062': "b", '\\u0031': "1" }; -const c = { +a = { c1: "c1", 'c2': "c2" }; -const d = { +a = { d1: "d1", 'd-2': "d2" }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -336,7 +336,7 @@ const e = { 2n: null, } -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -391,33 +391,38 @@ Object.entries({ "-1.5": null, } +a = { + "\\a": 1, + "b": 2 +} + =====================================output===================================== -const a = { +a = { a: "a", }; -const b = { +a = { b: "b", }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. "\\u0062": "b", "\\u0031": "1", }; -const c = { +a = { c1: "c1", c2: "c2", }; -const d = { +a = { d1: "d1", "d-2": "d2", }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -435,7 +440,7 @@ const e = { 2n: null, }; -const f = { +a = { // These should be unquoted for quoteProps=as-needed. NaN: null, 1: null, @@ -490,6 +495,11 @@ Object.entries({ "-1.5": null, }; +a = { + a: 1, + b: 2, +}; + ================================================================================ `; @@ -501,32 +511,32 @@ quoteProps: "consistent" singleQuote: true | printWidth =====================================input====================================== -const a = { +a = { a: "a" }; -const b = { +a = { 'b': "b" }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. '\\u0062': "b", '\\u0031': "1" }; -const c = { +a = { c1: "c1", 'c2': "c2" }; -const d = { +a = { d1: "d1", 'd-2': "d2" }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -544,7 +554,7 @@ const e = { 2n: null, } -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -599,33 +609,38 @@ Object.entries({ "-1.5": null, } +a = { + "\\a": 1, + "b": 2 +} + =====================================output===================================== -const a = { +a = { a: 'a', }; -const b = { +a = { b: 'b', }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. '\\u0062': 'b', '\\u0031': '1', }; -const c = { +a = { c1: 'c1', c2: 'c2', }; -const d = { +a = { 'd1': 'd1', 'd-2': 'd2', }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -643,7 +658,7 @@ const e = { 2n: null, }; -const f = { +a = { // These should be unquoted for quoteProps=as-needed. 'NaN': null, '1': null, @@ -698,6 +713,11 @@ Object.entries({ '-1.5': null, }; +a = { + a: 1, + b: 2, +}; + ================================================================================ `; @@ -708,32 +728,32 @@ printWidth: 80 quoteProps: "consistent" | printWidth =====================================input====================================== -const a = { +a = { a: "a" }; -const b = { +a = { 'b': "b" }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. '\\u0062': "b", '\\u0031': "1" }; -const c = { +a = { c1: "c1", 'c2': "c2" }; -const d = { +a = { d1: "d1", 'd-2': "d2" }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -751,7 +771,7 @@ const e = { 2n: null, } -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -806,33 +826,38 @@ Object.entries({ "-1.5": null, } +a = { + "\\a": 1, + "b": 2 +} + =====================================output===================================== -const a = { +a = { a: "a", }; -const b = { +a = { b: "b", }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. "\\u0062": "b", "\\u0031": "1", }; -const c = { +a = { c1: "c1", c2: "c2", }; -const d = { +a = { "d1": "d1", "d-2": "d2", }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -850,7 +875,7 @@ const e = { 2n: null, }; -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -905,6 +930,11 @@ Object.entries({ "-1.5": null, }; +a = { + a: 1, + b: 2, +}; + ================================================================================ `; @@ -915,32 +945,32 @@ printWidth: 80 quoteProps: "preserve" | printWidth =====================================input====================================== -const a = { +a = { a: "a" }; -const b = { +a = { 'b': "b" }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. '\\u0062': "b", '\\u0031': "1" }; -const c = { +a = { c1: "c1", 'c2': "c2" }; -const d = { +a = { d1: "d1", 'd-2': "d2" }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -958,7 +988,7 @@ const e = { 2n: null, } -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -1013,33 +1043,38 @@ Object.entries({ "-1.5": null, } +a = { + "\\a": 1, + "b": 2 +} + =====================================output===================================== -const a = { +a = { a: "a", }; -const b = { +a = { "b": "b", }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. "\\u0062": "b", "\\u0031": "1", }; -const c = { +a = { c1: "c1", "c2": "c2", }; -const d = { +a = { d1: "d1", "d-2": "d2", }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -1057,7 +1092,7 @@ const e = { 2n: null, }; -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -1112,6 +1147,11 @@ Object.entries({ "-1.5": null, }; +a = { + "a": 1, + "b": 2, +}; + ================================================================================ `; diff --git a/tests/format/js/quote-props/jsfmt.spec.js b/tests/format/js/quote-props/jsfmt.spec.js index 2457d95416b9..80d7cae87917 100644 --- a/tests/format/js/quote-props/jsfmt.spec.js +++ b/tests/format/js/quote-props/jsfmt.spec.js @@ -1,22 +1,7 @@ -const errors = {}; - -runFormatTest(import.meta, ["babel"], { - quoteProps: "as-needed", - errors, -}); - -runFormatTest(import.meta, ["babel"], { - quoteProps: "preserve", - errors, -}); - -runFormatTest(import.meta, ["babel"], { - quoteProps: "consistent", - errors, -}); - +runFormatTest(import.meta, ["babel"], { quoteProps: "as-needed" }); +runFormatTest(import.meta, ["babel"], { quoteProps: "preserve" }); +runFormatTest(import.meta, ["babel"], { quoteProps: "consistent" }); runFormatTest(import.meta, ["babel"], { quoteProps: "consistent", singleQuote: true, - errors, }); diff --git a/tests/format/js/quote-props/objects.js b/tests/format/js/quote-props/objects.js index 1320543c4bf9..40cdc863c228 100644 --- a/tests/format/js/quote-props/objects.js +++ b/tests/format/js/quote-props/objects.js @@ -1,29 +1,29 @@ -const a = { +a = { a: "a" }; -const b = { +a = { 'b': "b" }; -const b2 = { +a = { // Escapes should stay as escapes and not be unquoted. '\u0062': "b", '\u0031': "1" }; -const c = { +a = { c1: "c1", 'c2': "c2" }; -const d = { +a = { d1: "d1", 'd-2': "d2" }; // None of these should become quoted, regardless of the quoteProps value. -const e = { +a = { NaN: null, 1: null, 1.5: null, @@ -41,7 +41,7 @@ const e = { 2n: null, } -const f = { +a = { // These should be unquoted for quoteProps=as-needed. "NaN": null, "1": null, @@ -95,3 +95,8 @@ Object.entries({ "-1": null, "-1.5": null, } + +a = { + "\a": 1, + "b": 2 +}