From 7d80bae76a1ed0dcbfc0e51f3e0b77fc0cb35661 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Sat, 17 Oct 2020 00:51:00 +0800 Subject: [PATCH] Consistent format on invalid template literals (#9431) --- changelog_unreleased/javascript/pr-9431.md | 21 ++++++ src/language-js/embed.js | 20 +++-- .../__snapshots__/jsfmt.spec.js.snap | 75 +++++++++++++++++++ tests/js/multiparser-invalid/jsfmt.spec.js | 3 + tests/js/multiparser-invalid/text.js | 31 ++++++++ 5 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 changelog_unreleased/javascript/pr-9431.md create mode 100644 tests/js/multiparser-invalid/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/js/multiparser-invalid/jsfmt.spec.js create mode 100644 tests/js/multiparser-invalid/text.js diff --git a/changelog_unreleased/javascript/pr-9431.md b/changelog_unreleased/javascript/pr-9431.md new file mode 100644 index 000000000..b3233bf01 --- /dev/null +++ b/changelog_unreleased/javascript/pr-9431.md @@ -0,0 +1,21 @@ +#### Keep html and markdown invalid template literals as it is (#9431 by @fisker) + + +```js +// Input +foo = html`
\u{prettier}
`; +foo = html`\u{prettier}${foo}pr\u{0065}ttier`; +foo = markdown`# \u{prettier}\u{0065}`; + +// Prettier stable +foo = html``; +foo = html`null${foo}prettier`; +foo = markdown` +# \u{prettier}\u{0065} +`; + +// Prettier master +foo = html`
\u{prettier}
`; +foo = html`\u{prettier}${foo}pr\u{0065}ttier`; +foo = markdown`# \u{prettier}\u{0065}`; +``` diff --git a/src/language-js/embed.js b/src/language-js/embed.js index 371642fb5..eb7aba3da 100644 --- a/src/language-js/embed.js +++ b/src/language-js/embed.js @@ -24,6 +24,12 @@ function embed(path, print, textToDoc, options) { switch (node.type) { case "TemplateLiteral": { + // Bail out if any of the quasis have an invalid escape sequence + // (which would make the `cooked` value be `null`) + if (hasInvalidCookedValue(node)) { + return; + } + const isCss = [ isStyledJsx, isStyledComponents, @@ -69,7 +75,6 @@ function embed(path, print, textToDoc, options) { const expressionDocs = path.map(printTemplateExpression, "expressions"); const numQuasis = node.quasis.length; - if (numQuasis === 1 && node.quasis[0].value.raw.trim() === "") { return "``"; } @@ -82,12 +87,6 @@ function embed(path, print, textToDoc, options) { const isLast = i === numQuasis - 1; const text = templateElement.value.cooked; - // Bail out if any of the quasis have an invalid escape sequence - // (which would make the `cooked` value be `null` or `undefined`) - if (typeof text !== "string") { - return null; - } - const lines = text.split("\n"); const numLines = lines.length; const expressionDoc = expressionDocs[i]; @@ -166,6 +165,9 @@ function embed(path, print, textToDoc, options) { } case "TemplateElement": { + if (hasInvalidCookedValue(parent)) { + return; + } /** * md`...` * markdown`...` @@ -662,4 +664,8 @@ function printHtmlTemplateLiteral( ); } +function hasInvalidCookedValue({ quasis }) { + return quasis.some(({ value: { cooked } }) => cooked === null); +} + module.exports = embed; diff --git a/tests/js/multiparser-invalid/__snapshots__/jsfmt.spec.js.snap b/tests/js/multiparser-invalid/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000..437f6e376 --- /dev/null +++ b/tests/js/multiparser-invalid/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`text.js format 1`] = ` +====================================options===================================== +parsers: ["babel", "flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +foo = foo\`\\u{prettier}\\u{0065}\`; +foo = html\`\\u{prettier}\\u{0065}\`; +foo = graphql\`\\u{prettier}\\u{0065}\`; +foo = markdown\`\\u{prettier}\\u{0065}\`; +foo = css\`\\u{prettier}\\u{0065}\`; +foo = /* HTML */\`\\u{prettier}\\u{0065}\`; +foo = /* GraphQL */\`\\u{prettier}\\u{0065}\`; + +foo = foo\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = html\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = graphql\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = markdown\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = css\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = /* HTML */\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = /* GraphQL */\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; + +foo = foo\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = html\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = graphql\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = markdown\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = css\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = /* HTML */\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = /* GraphQL */\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; + +foo = foo\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = html\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = graphql\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = markdown\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = css\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = /* HTML */\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = /* GraphQL */\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; + +=====================================output===================================== +foo = foo\`\\u{prettier}\\u{0065}\`; +foo = html\`\\u{prettier}\\u{0065}\`; +foo = graphql\`\\u{prettier}\\u{0065}\`; +foo = markdown\`\\u{prettier}\\u{0065}\`; +foo = css\`\\u{prettier}\\u{0065}\`; +foo = /* HTML */ \`\\u{prettier}\\u{0065}\`; +foo = /* GraphQL */ \`\\u{prettier}\\u{0065}\`; + +foo = foo\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = html\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = graphql\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = markdown\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = css\`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = /* HTML */ \`\\u{prettier}\${foo}pr\\u{0065}ttier\`; +foo = /* GraphQL */ \`\\u{prettier}\${foo}pr\\u{0065}ttier\`; + +foo = foo\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = html\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = graphql\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = markdown\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = css\`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = /* HTML */ \`pr\\u{0065}ttier\${foo}\\u{prettier}\`; +foo = /* GraphQL */ \`pr\\u{0065}ttier\${foo}\\u{prettier}\`; + +foo = foo\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = html\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = graphql\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = markdown\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = css\`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = /* HTML */ \`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; +foo = /* GraphQL */ \`pr\\u{0065}ttier\${foo}\\u{prettier}\${bar}pr\\u{0065}ttier\`; + +================================================================================ +`; diff --git a/tests/js/multiparser-invalid/jsfmt.spec.js b/tests/js/multiparser-invalid/jsfmt.spec.js new file mode 100644 index 000000000..6e2b8e1a6 --- /dev/null +++ b/tests/js/multiparser-invalid/jsfmt.spec.js @@ -0,0 +1,3 @@ +run_spec(__dirname, ["babel", "flow", "typescript"], { + errors: { espree: true, flow: true, typescript: true }, +}); diff --git a/tests/js/multiparser-invalid/text.js b/tests/js/multiparser-invalid/text.js new file mode 100644 index 000000000..37a612ed5 --- /dev/null +++ b/tests/js/multiparser-invalid/text.js @@ -0,0 +1,31 @@ +foo = foo`\u{prettier}\u{0065}`; +foo = html`\u{prettier}\u{0065}`; +foo = graphql`\u{prettier}\u{0065}`; +foo = markdown`\u{prettier}\u{0065}`; +foo = css`\u{prettier}\u{0065}`; +foo = /* HTML */`\u{prettier}\u{0065}`; +foo = /* GraphQL */`\u{prettier}\u{0065}`; + +foo = foo`\u{prettier}${foo}pr\u{0065}ttier`; +foo = html`\u{prettier}${foo}pr\u{0065}ttier`; +foo = graphql`\u{prettier}${foo}pr\u{0065}ttier`; +foo = markdown`\u{prettier}${foo}pr\u{0065}ttier`; +foo = css`\u{prettier}${foo}pr\u{0065}ttier`; +foo = /* HTML */`\u{prettier}${foo}pr\u{0065}ttier`; +foo = /* GraphQL */`\u{prettier}${foo}pr\u{0065}ttier`; + +foo = foo`pr\u{0065}ttier${foo}\u{prettier}`; +foo = html`pr\u{0065}ttier${foo}\u{prettier}`; +foo = graphql`pr\u{0065}ttier${foo}\u{prettier}`; +foo = markdown`pr\u{0065}ttier${foo}\u{prettier}`; +foo = css`pr\u{0065}ttier${foo}\u{prettier}`; +foo = /* HTML */`pr\u{0065}ttier${foo}\u{prettier}`; +foo = /* GraphQL */`pr\u{0065}ttier${foo}\u{prettier}`; + +foo = foo`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`; +foo = html`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`; +foo = graphql`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`; +foo = markdown`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`; +foo = css`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`; +foo = /* HTML */`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`; +foo = /* GraphQL */`pr\u{0065}ttier${foo}\u{prettier}${bar}pr\u{0065}ttier`;