From 6b582a061992ee614631b0ff196d92faad86c6c3 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 4 Nov 2024 15:24:02 +0800 Subject: [PATCH] Improve string print perfomance (#16763) --- changelog_unreleased/javascript/16563.md | 4 ++-- src/utils/print-string.js | 9 ++++++++ .../quotes/__snapshots__/format.test.js.snap | 12 +++++----- .../quotes/__snapshots__/format.test.js.snap | 20 ++++++++--------- .../strings/__snapshots__/format.test.js.snap | 22 +++++++++++++++---- tests/format/js/strings/escaped.js | 3 +++ 6 files changed, 48 insertions(+), 22 deletions(-) diff --git a/changelog_unreleased/javascript/16563.md b/changelog_unreleased/javascript/16563.md index 349ca3b6f..6b277ba81 100644 --- a/changelog_unreleased/javascript/16563.md +++ b/changelog_unreleased/javascript/16563.md @@ -1,4 +1,4 @@ -#### Don't remove useless `\` in string literals (#16563 by @sosukesuzuki) +#### Don't remove useless `\` in string literals (#16563 by @sosukesuzuki, #16763 by @fisker) Previously, Prettier would remove useless escape characters (`\`) from string literals. However, this behavior was inconsistent as it did not apply to template literals, which was reported in [issue #16542](https://github.com/prettier/prettier/issues/16542). @@ -8,7 +8,7 @@ After discussing this internally, the Prettier team concluded that removing usel This change disables the removal of useless escape characters in string literals across all languages supported by Prettier. To keep the previous behavior, we recommend using ESLint rules like [`no-useless-escape`](https://eslint.org/docs/latest/rules/no-useless-escape). -Escaping quotes within string literals (e.g. `"\"\'"`) works the same as before. This is explained on the [Rationale](https://prettier.io/docs/en/rationale.html#strings) page of the official documentation. +Escaped quotes (e.g. `"\"\'"`) may get unescaped when changing between different quotes. This is explained on the [Rationale](https://prettier.io/docs/en/rationale.html#strings) page of the official documentation. ```jsx diff --git a/src/utils/print-string.js b/src/utils/print-string.js index c69b40263..7202bc6ac 100644 --- a/src/utils/print-string.js +++ b/src/utils/print-string.js @@ -1,9 +1,12 @@ +import assert from "node:assert"; import getPreferredQuote from "./get-preferred-quote.js"; import makeString from "./make-string.js"; /** @import {Quote} from "./get-preferred-quote.js" */ function printString(raw, options) { + assert(/^(?["']).*\k$/su.test(raw)); + // `rawContent` is the string exactly like it appeared in the input source // code, without its enclosing quotes. const rawContent = raw.slice(1, -1); @@ -26,6 +29,12 @@ function printString(raw, options) { ? "'" : getPreferredQuote(rawContent, options.singleQuote); + const originalQuote = raw.charAt(0); + + if (originalQuote === enclosingQuote) { + return raw; + } + // It might sound unnecessary to use `makeString` even if the string already // is enclosed with `enclosingQuote`, but it isn't. The string could contain // unnecessary escapes (such as in `"\'"`). Always using `makeString` makes diff --git a/tests/format/css/quotes/__snapshots__/format.test.js.snap b/tests/format/css/quotes/__snapshots__/format.test.js.snap index 67eed4b42..b4baa9988 100644 --- a/tests/format/css/quotes/__snapshots__/format.test.js.snap +++ b/tests/format/css/quotes/__snapshots__/format.test.js.snap @@ -137,7 +137,7 @@ one 'two' three {} /* One of each with unnecessary escapes. */ content: '"\\''; - content: '"\\''; + content: '\\"\\''; /* More double quotes than single quotes. */ content: '"\\'"'; @@ -156,8 +156,8 @@ one 'two' three {} content: '\\\\'; /* Backslases. */ - content: "\\"\\\\\\"\\\\\\\\\\" ''\\\\'\\\\'\\\\\\\\'"; - content: '\\'\\\\\\'\\\\\\\\\\' ""\\\\"\\\\"\\\\\\\\"'; + content: "\\"\\\\\\"\\\\\\\\\\" '\\'\\\\'\\\\\\'\\\\\\\\'"; + content: '\\'\\\\\\'\\\\\\\\\\' "\\"\\\\"\\\\\\"\\\\\\\\"'; /* Somewhat more real-word example. */ content: "He's sayin': \\"How's it goin'?\\" Don't ask me why."; @@ -332,7 +332,7 @@ one 'two' three {} content: "\\"'"; /* One of each with unnecessary escapes. */ - content: "\\"'"; + content: "\\"\\'"; content: "\\"'"; /* More double quotes than single quotes. */ @@ -352,8 +352,8 @@ one 'two' three {} content: "\\\\"; /* Backslases. */ - content: "\\"\\\\\\"\\\\\\\\\\" ''\\\\'\\\\'\\\\\\\\'"; - content: '\\'\\\\\\'\\\\\\\\\\' ""\\\\"\\\\"\\\\\\\\"'; + content: "\\"\\\\\\"\\\\\\\\\\" '\\'\\\\'\\\\\\'\\\\\\\\'"; + content: '\\'\\\\\\'\\\\\\\\\\' "\\"\\\\"\\\\\\"\\\\\\\\"'; /* Somewhat more real-word example. */ content: "He's sayin': \\"How's it goin'?\\" Don't ask me why."; diff --git a/tests/format/js/quotes/__snapshots__/format.test.js.snap b/tests/format/js/quotes/__snapshots__/format.test.js.snap index c7e491779..b16a66fd8 100644 --- a/tests/format/js/quotes/__snapshots__/format.test.js.snap +++ b/tests/format/js/quotes/__snapshots__/format.test.js.snap @@ -234,8 +234,8 @@ singleQuote: true ("'"); // Unnecessary escapes. -("'"); -('"'); +("\\'"); +('\\"'); ('\\a'); ('\\a'); ('hol\\a'); @@ -270,7 +270,7 @@ singleQuote: true // One of each with unnecessary escapes. ('"\\''); -('"\\''); +('\\"\\''); // More double quotes than single quotes. ('"\\'"'); @@ -289,8 +289,8 @@ singleQuote: true ('\\\\'); // Backslases. -("\\"\\\\\\"\\\\\\\\\\" ''\\\\'\\\\'\\\\\\\\'"); -('\\'\\\\\\'\\\\\\\\\\' ""\\\\"\\\\"\\\\\\\\"'); +("\\"\\\\\\"\\\\\\\\\\" '\\'\\\\'\\\\\\'\\\\\\\\'"); +('\\'\\\\\\'\\\\\\\\\\' "\\"\\\\"\\\\\\"\\\\\\\\"'); // Somewhat more real-word example. ("He's sayin': \\"How's it goin'?\\" Don't ask me why."); @@ -446,8 +446,8 @@ printWidth: 80 ("'"); // Unnecessary escapes. -("'"); -('"'); +("\\'"); +('\\"'); ("\\a"); ("\\a"); ("hol\\a"); @@ -481,7 +481,7 @@ printWidth: 80 ("\\"'"); // One of each with unnecessary escapes. -("\\"'"); +("\\"\\'"); ("\\"'"); // More double quotes than single quotes. @@ -501,8 +501,8 @@ printWidth: 80 ("\\\\"); // Backslases. -("\\"\\\\\\"\\\\\\\\\\" ''\\\\'\\\\'\\\\\\\\'"); -('\\'\\\\\\'\\\\\\\\\\' ""\\\\"\\\\"\\\\\\\\"'); +("\\"\\\\\\"\\\\\\\\\\" '\\'\\\\'\\\\\\'\\\\\\\\'"); +('\\'\\\\\\'\\\\\\\\\\' "\\"\\\\"\\\\\\"\\\\\\\\"'); // Somewhat more real-word example. ("He's sayin': \\"How's it goin'?\\" Don't ask me why."); diff --git a/tests/format/js/strings/__snapshots__/format.test.js.snap b/tests/format/js/strings/__snapshots__/format.test.js.snap index 7d9d43da8..aa211aad8 100644 --- a/tests/format/js/strings/__snapshots__/format.test.js.snap +++ b/tests/format/js/strings/__snapshots__/format.test.js.snap @@ -11,6 +11,9 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = + goog.getMsg('That\\'s all we know'); + +export const MSG_GENERIC_OPERATION_FAILURE_BODY_3 = goog.getMsg("That\\'s all we know"); =====================================output===================================== @@ -20,6 +23,10 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg("That's all we know"); +export const MSG_GENERIC_OPERATION_FAILURE_BODY_3 = goog.getMsg( + "That\\'s all we know", +); + ================================================================================ `; @@ -34,6 +41,9 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = + goog.getMsg('That\\'s all we know'); + +export const MSG_GENERIC_OPERATION_FAILURE_BODY_3 = goog.getMsg("That\\'s all we know"); =====================================output===================================== @@ -43,6 +53,10 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg("That's all we know"); +export const MSG_GENERIC_OPERATION_FAILURE_BODY_3 = goog.getMsg( + "That\\'s all we know" +); + ================================================================================ `; @@ -279,11 +293,11 @@ trailingComma: "all" "'", '"', - '"', + '\\"', '\\\\"', "'", - "'", + "\\'", "\\\\'", "'\\"", @@ -342,11 +356,11 @@ trailingComma: "es5" "'", '"', - '"', + '\\"', '\\\\"', "'", - "'", + "\\'", "\\\\'", "'\\"", diff --git a/tests/format/js/strings/escaped.js b/tests/format/js/strings/escaped.js index 118095cc5..b2d2b1baf 100644 --- a/tests/format/js/strings/escaped.js +++ b/tests/format/js/strings/escaped.js @@ -2,4 +2,7 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = + goog.getMsg('That\'s all we know'); + +export const MSG_GENERIC_OPERATION_FAILURE_BODY_3 = goog.getMsg("That\'s all we know");