diff --git a/src/printer.js b/src/printer.js index de92d7510..f62728040 100644 --- a/src/printer.js +++ b/src/printer.js @@ -3917,8 +3917,15 @@ function makeString(rawContent, enclosingQuote) { return "\\" + quote; } - // Otherwise return the escape or unescaped quote as-is. - return match; + if (quote) { + return quote; + } + + // Unescape any unnecessarily escaped character. + // Adapted from https://github.com/eslint/eslint/blob/de0b4ad7bd820ade41b1f606008bea68683dc11a/lib/rules/no-useless-escape.js#L27 + return /^[^\\nrvtbfux\r\n\u2028\u2029"'0-7]$/.test(escaped) + ? escaped + : "\\" + escaped; }); return enclosingQuote + newContent + enclosingQuote; diff --git a/tests/directives/__snapshots__/jsfmt.spec.js.snap b/tests/directives/__snapshots__/jsfmt.spec.js.snap index b7e1f0373..342de6894 100644 --- a/tests/directives/__snapshots__/jsfmt.spec.js.snap +++ b/tests/directives/__snapshots__/jsfmt.spec.js.snap @@ -1,19 +1,77 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`escaped.js 1`] = ` +// Unnecessary escapes. (adapted from tests/quotes/strings.js) +// Note that in directives, unnecessary escapes should be preserved. +// See https://github.com/prettier/prettier/issues/1555 '\\''; '\\"'; "\\'"; "\\""; '\\\\'; '\\a'; +"hol\\a" +'hol\\a' +"hol\\\\a (the a is not escaped)" +'hol\\\\a (the a is not escaped)' +"multiple \\a unnecessary \\a escapes" +'multiple \\a unnecessary \\a escapes' +"unnecessarily escaped character preceded by escaped backslash \\\\\\a" +'unnecessarily escaped character preceded by escaped backslash \\\\\\a' +"unescaped character preceded by two escaped backslashes \\\\\\\\a" +'unescaped character preceded by two escaped backslashes \\\\\\\\a' +"\\a\\a" // consecutive unnecessarily escaped characters +'\\a\\a' // consecutive unnecessarily escaped characters +'escaped \\u2030 \\‰ (should still stay escaped)' + +// Meaningful escapes +// Commented out to avoid \`SyntaxError: Octal literals are not allowed in strict mode.\` +// "octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7" +// 'octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7' +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61" +'meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61' +'escaped newline \\ +' +'escaped carriage return \\ +' +'escaped \\u2028 \\
' +'escaped \\u2029 \\
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Unnecessary escapes. (adapted from tests/quotes/strings.js) +// Note that in directives, unnecessary escapes should be preserved. +// See https://github.com/prettier/prettier/issues/1555 '\\''; '\\"'; "\\'"; "\\""; "\\\\"; "\\a"; +"hol\\a"; +"hol\\a"; +"hol\\\\a (the a is not escaped)"; +"hol\\\\a (the a is not escaped)"; +"multiple \\a unnecessary \\a escapes"; +"multiple \\a unnecessary \\a escapes"; +"unnecessarily escaped character preceded by escaped backslash \\\\\\a"; +"unnecessarily escaped character preceded by escaped backslash \\\\\\a"; +"unescaped character preceded by two escaped backslashes \\\\\\\\a"; +"unescaped character preceded by two escaped backslashes \\\\\\\\a"; +"\\a\\a"; // consecutive unnecessarily escaped characters +"\\a\\a"; // consecutive unnecessarily escaped characters +"escaped \\u2030 \\‰ (should still stay escaped)"; + +// Meaningful escapes +// Commented out to avoid \`SyntaxError: Octal literals are not allowed in strict mode.\` +// "octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7" +// 'octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7' +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61"; +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61"; +"escaped newline \\ +"; +"escaped carriage return \\ +"; +"escaped \\u2028 \\
"; +"escaped \\u2029 \\
"; `; diff --git a/tests/directives/escaped.js b/tests/directives/escaped.js index 67fb803fb..8894f70a6 100644 --- a/tests/directives/escaped.js +++ b/tests/directives/escaped.js @@ -1,6 +1,35 @@ +// Unnecessary escapes. (adapted from tests/quotes/strings.js) +// Note that in directives, unnecessary escapes should be preserved. +// See https://github.com/prettier/prettier/issues/1555 '\''; '\"'; "\'"; "\""; '\\'; '\a'; +"hol\a" +'hol\a' +"hol\\a (the a is not escaped)" +'hol\\a (the a is not escaped)' +"multiple \a unnecessary \a escapes" +'multiple \a unnecessary \a escapes' +"unnecessarily escaped character preceded by escaped backslash \\\a" +'unnecessarily escaped character preceded by escaped backslash \\\a' +"unescaped character preceded by two escaped backslashes \\\\a" +'unescaped character preceded by two escaped backslashes \\\\a' +"\a\a" // consecutive unnecessarily escaped characters +'\a\a' // consecutive unnecessarily escaped characters +'escaped \u2030 \‰ (should still stay escaped)' + +// Meaningful escapes +// Commented out to avoid `SyntaxError: Octal literals are not allowed in strict mode.` +// "octal escapes \0 \1 \2 \3 \4 \5 \6 \7" +// 'octal escapes \0 \1 \2 \3 \4 \5 \6 \7' +"meaningfully escaped alphabetical characters \n \r \v \t \b \f \u2713 \x61" +'meaningfully escaped alphabetical characters \n \r \v \t \b \f \u2713 \x61' +'escaped newline \ +' +'escaped carriage return \ +' +'escaped \u2028 \
' +'escaped \u2029 \
' diff --git a/tests/quotes/__snapshots__/jsfmt.spec.js.snap b/tests/quotes/__snapshots__/jsfmt.spec.js.snap index f5ead8960..558c9e1e4 100644 --- a/tests/quotes/__snapshots__/jsfmt.spec.js.snap +++ b/tests/quotes/__snapshots__/jsfmt.spec.js.snap @@ -68,6 +68,33 @@ exports[`strings.js 1`] = ` // Unnecessary escapes. "\\'" '\\"' +"\\a" +'\\a' +"hol\\a" +'hol\\a' +"hol\\\\a (the a is not escaped)" +'hol\\\\a (the a is not escaped)' +"multiple \\a unnecessary \\a escapes" +'multiple \\a unnecessary \\a escapes' +"unnecessarily escaped character preceded by escaped backslash \\\\\\a" +'unnecessarily escaped character preceded by escaped backslash \\\\\\a' +"unescaped character preceded by two escaped backslashes \\\\\\\\a" +'unescaped character preceded by two escaped backslashes \\\\\\\\a' +"\\a\\a" // consecutive unnecessarily escaped characters +'\\a\\a' // consecutive unnecessarily escaped characters +'escaped \\u2030 \\‰ (should not stay escaped)' + +// Meaningful escapes +"octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7" +'octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7' +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61" +'meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61' +'escaped newline \\ +' +'escaped carriage return \\ +' +'escaped \\u2028 \\
' +'escaped \\u2029 \\
' // One of each. "\\"'" @@ -138,6 +165,32 @@ exports[`strings.js 1`] = ` // Unnecessary escapes. "'"; '"'; +"a"; +"a"; +"hola"; +"hola"; +"hol\\\\a (the a is not escaped)"; +"hol\\\\a (the a is not escaped)"; +"multiple a unnecessary a escapes"; +"multiple a unnecessary a escapes"; +"unnecessarily escaped character preceded by escaped backslash \\\\a"; +"unnecessarily escaped character preceded by escaped backslash \\\\a"; +"unescaped character preceded by two escaped backslashes \\\\\\\\a"; +"unescaped character preceded by two escaped backslashes \\\\\\\\a"; +"aa"; // consecutive unnecessarily escaped characters +"aa"; // consecutive unnecessarily escaped characters +"escaped \\u2030 ‰ (should not stay escaped)"; +// Meaningful escapes +"octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7"; +"octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7"; +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61"; +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61"; +"escaped newline \\ +"; +"escaped carriage return \\ +"; +"escaped \\u2028 \\
"; +"escaped \\u2029 \\
"; // One of each. "\\"'"; "\\"'"; @@ -206,6 +259,33 @@ exports[`strings.js 2`] = ` // Unnecessary escapes. "\\'" '\\"' +"\\a" +'\\a' +"hol\\a" +'hol\\a' +"hol\\\\a (the a is not escaped)" +'hol\\\\a (the a is not escaped)' +"multiple \\a unnecessary \\a escapes" +'multiple \\a unnecessary \\a escapes' +"unnecessarily escaped character preceded by escaped backslash \\\\\\a" +'unnecessarily escaped character preceded by escaped backslash \\\\\\a' +"unescaped character preceded by two escaped backslashes \\\\\\\\a" +'unescaped character preceded by two escaped backslashes \\\\\\\\a' +"\\a\\a" // consecutive unnecessarily escaped characters +'\\a\\a' // consecutive unnecessarily escaped characters +'escaped \\u2030 \\‰ (should not stay escaped)' + +// Meaningful escapes +"octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7" +'octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7' +"meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61" +'meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61' +'escaped newline \\ +' +'escaped carriage return \\ +' +'escaped \\u2028 \\
' +'escaped \\u2029 \\
' // One of each. "\\"'" @@ -276,6 +356,32 @@ exports[`strings.js 2`] = ` // Unnecessary escapes. "'"; '"'; +'a'; +'a'; +'hola'; +'hola'; +'hol\\\\a (the a is not escaped)'; +'hol\\\\a (the a is not escaped)'; +'multiple a unnecessary a escapes'; +'multiple a unnecessary a escapes'; +'unnecessarily escaped character preceded by escaped backslash \\\\a'; +'unnecessarily escaped character preceded by escaped backslash \\\\a'; +'unescaped character preceded by two escaped backslashes \\\\\\\\a'; +'unescaped character preceded by two escaped backslashes \\\\\\\\a'; +'aa'; // consecutive unnecessarily escaped characters +'aa'; // consecutive unnecessarily escaped characters +'escaped \\u2030 ‰ (should not stay escaped)'; +// Meaningful escapes +'octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7'; +'octal escapes \\0 \\1 \\2 \\3 \\4 \\5 \\6 \\7'; +'meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61'; +'meaningfully escaped alphabetical characters \\n \\r \\v \\t \\b \\f \\u2713 \\x61'; +'escaped newline \\ +'; +'escaped carriage return \\ +'; +'escaped \\u2028 \\
'; +'escaped \\u2029 \\
'; // One of each. '"\\''; '"\\''; diff --git a/tests/quotes/strings.js b/tests/quotes/strings.js index 163724232..34c5b921e 100644 --- a/tests/quotes/strings.js +++ b/tests/quotes/strings.js @@ -35,6 +35,33 @@ // Unnecessary escapes. "\'" '\"' +"\a" +'\a' +"hol\a" +'hol\a' +"hol\\a (the a is not escaped)" +'hol\\a (the a is not escaped)' +"multiple \a unnecessary \a escapes" +'multiple \a unnecessary \a escapes' +"unnecessarily escaped character preceded by escaped backslash \\\a" +'unnecessarily escaped character preceded by escaped backslash \\\a' +"unescaped character preceded by two escaped backslashes \\\\a" +'unescaped character preceded by two escaped backslashes \\\\a' +"\a\a" // consecutive unnecessarily escaped characters +'\a\a' // consecutive unnecessarily escaped characters +'escaped \u2030 \‰ (should not stay escaped)' + +// Meaningful escapes +"octal escapes \0 \1 \2 \3 \4 \5 \6 \7" +'octal escapes \0 \1 \2 \3 \4 \5 \6 \7' +"meaningfully escaped alphabetical characters \n \r \v \t \b \f \u2713 \x61" +'meaningfully escaped alphabetical characters \n \r \v \t \b \f \u2713 \x61' +'escaped newline \ +' +'escaped carriage return \ +' +'escaped \u2028 \
' +'escaped \u2029 \
' // One of each. "\"'"