Repository: prettier/prettier (JavaScript)
Date: 2024-05-08 07:37:47+00:00
Task type: Bug Fix

Issue:
dynamic import keyword is removed when given multiline template string
<!--

BEFORE SUBMITTING AN ISSUE:

1.  Search for your issue on GitHub: https://github.com/prettier/prettier/issues
    A large number of opened issues are duplicates of existing issues.
    If someone has already opened an issue for what you are experiencing,
    you do not need to open a new issue — please add a 👍 reaction to the
    existing issue instead.

2.  We get a lot of requests for adding options, but Prettier is
    built on the principle of being opinionated about code formatting.
    This means we add options only in the case of strict technical necessity.
    Find out more: https://prettier.io/docs/en/option-philosophy.html

Don't fill the form below manually! Let a program create a report for you:

1. Go to https://prettier.io/playground
2. Paste your code and set options
3. Press the "Report issue" button in the lower right

-->

**Prettier 3.2.5**

[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuc0DOMAEBbCATAVwBs5MBeTAQwHdKBLLO7ABwgCcYAKAAz0pkpJ4ADxgB6AFaUAbpTRg2dZjAA0AHSiYtmSFDQQSAOiIQA5pzUgASgFUAcpYCUAbg3cXIFSAjK66ZKCUbGwQ1AAKQQhoyCCURLQAntFeAEZslGAA1nAwAMqU2HAAMnRQcMgAZnFocKnpWTm5zBmlpsgwbAS1IDXYdO2d3XDCzHCKhbBxACpjUEF0cNFIVUQ1XmitJACKBBDwldXdEmjCuZtwO3vly4deAI678GEhzEuxaAC0ZXB4P54gHXoRFaAGEINhsJQYnEiP8NlBTCQAIIwDp0FIEJ5jEplA6rboACxg2CIAHUCQxFs0wHBclEGHRpAwEjEwGhkiBpF0AJJQX6wXIKJQwJF83IwBIkPFrEDMEI1UnpZgxOWLMbScpeUo1DjPSimSHS7rNNg6mIS0byRTKf5y0owUl0PAwAnIAAcAAYvGw4A86D69QaoTd8V4BClHc7XUgAExeAg1KaUFJLFYyuDYFI-X54IqUBEEfVwABi7EhqNa0MxEBAAF9a0A)


**Input:**

```ts
const module = await import(`data:text/javascript,
    console.log("RUN");
`);
```

**Output:**

```jsx
const module = await (`data:text/javascript,
    console.log("RUN");
`);
```

**Expected output:**

```jsx
const module = await import(`data:text/javascript,
    console.log("RUN");
`);
```

**Why?**

The `import` keyword is deleted for no discernable reason.


Issue discussion:

Solution patch:
diff --git a/changelog_unreleased/javascript/16267.md b/changelog_unreleased/javascript/16267.md
new file mode 100644
index 000000000000..78471333fbf8
--- /dev/null
+++ b/changelog_unreleased/javascript/16267.md
@@ -0,0 +1,19 @@
+#### Fix dynamic import when the module source is a template string (#16267 by @fisker)
+
+<!-- prettier-ignore -->
+```jsx
+// Input
+const module = await import(`data:text/javascript,
+  console.log("RUN");
+`);
+
+// Prettier stable
+const module = await (`data:text/javascript,
+  console.log("RUN");
+`);
+
+// Prettier main
+const module = await import(`data:text/javascript,
+  console.log("RUN");
+`);
+```
diff --git a/src/language-js/print/call-expression.js b/src/language-js/print/call-expression.js
index ec1344fae310..7baac263de4c 100644
--- a/src/language-js/print/call-expression.js
+++ b/src/language-js/print/call-expression.js
@@ -45,7 +45,7 @@ function printCallExpression(path, options, print) {
     if (!(isTemplateLiteralSingleArg && printed[0].label?.embed)) {
       return [
         isNew ? "new " : "",
-        print("callee"),
+        isDynamicImport ? printDynamicImportCallee(node) : print("callee"),
         optional,
         printFunctionTypeParameters(path, options, print),
         "(",


Test patch:
diff --git a/tests/format/js/dynamic-import/__snapshots__/format.test.js.snap b/tests/format/js/dynamic-import/__snapshots__/format.test.js.snap
index 58413f20fa56..4b1fe2a4b4c6 100644
--- a/tests/format/js/dynamic-import/__snapshots__/format.test.js.snap
+++ b/tests/format/js/dynamic-import/__snapshots__/format.test.js.snap
@@ -45,6 +45,106 @@ import("./foo.json", { assert: { type: "json" } });
 ================================================================================
 `;
 
+exports[`import-phase.js [acorn] format 1`] = `
+"The only valid meta property for import is 'import.meta' (1:8)
+> 1 | import.source(\`data:text/javascript,
+    |        ^
+  2 |     console.log("RUN");
+  3 | \`)
+  4 |
+Cause: The only valid meta property for import is 'import.meta' (1:7)"
+`;
+
+exports[`import-phase.js [espree] format 1`] = `
+"The only valid meta property for import is 'import.meta' (1:8)
+> 1 | import.source(\`data:text/javascript,
+    |        ^
+  2 |     console.log("RUN");
+  3 | \`)
+  4 |
+Cause: The only valid meta property for import is 'import.meta'"
+`;
+
+exports[`import-phase.js [flow] format 1`] = `
+"Unexpected identifier, expected the identifier \`meta\` (1:8)
+> 1 | import.source(\`data:text/javascript,
+    |        ^^^^^^
+  2 |     console.log("RUN");
+  3 | \`)
+  4 |"
+`;
+
+exports[`import-phase.js [meriyah] format 1`] = `
+"Unexpected token: 'identifier' (1:13)
+> 1 | import.source(\`data:text/javascript,
+    |             ^
+  2 |     console.log("RUN");
+  3 | \`)
+  4 |
+Cause: [1:13]: Unexpected token: 'identifier'"
+`;
+
+exports[`import-phase.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+import.source(\`data:text/javascript,
+    console.log("RUN");
+\`)
+
+import.source(String.raw\`data:text/javascript,
+    console.log("RUN");
+\`)
+
+=====================================output=====================================
+import.source(\`data:text/javascript,
+    console.log("RUN");
+\`);
+
+import.source(String.raw\`data:text/javascript,
+    console.log("RUN");
+\`);
+
+================================================================================
+`;
+
+exports[`template-literal.js [flow] format 1`] = `
+"Unexpected token \`import\`, expected the end of an expression statement (\`;\`) (1:20)
+> 1 | module   =   await import(\`data:text/javascript,
+    |                    ^^^^^^
+  2 |     console.log("RUN");
+  3 | \`);
+  4 |"
+`;
+
+exports[`template-literal.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+module   =   await import(\`data:text/javascript,
+    console.log("RUN");
+\`);
+
+module   =   await import(String.raw\`data:text/javascript,
+    console.log("RUN");
+\`);
+
+=====================================output=====================================
+module = await import(\`data:text/javascript,
+    console.log("RUN");
+\`);
+
+module = await import(String.raw\`data:text/javascript,
+    console.log("RUN");
+\`);
+
+================================================================================
+`;
+
 exports[`test.js format 1`] = `
 ====================================options=====================================
 parsers: ["babel", "flow", "typescript"]
diff --git a/tests/format/js/dynamic-import/format.test.js b/tests/format/js/dynamic-import/format.test.js
index a08f4126d747..a73928c39c67 100644
--- a/tests/format/js/dynamic-import/format.test.js
+++ b/tests/format/js/dynamic-import/format.test.js
@@ -1,8 +1,8 @@
 runFormatTest(import.meta, ["babel", "flow", "typescript"], {
   errors: {
-    flow: ["assertions.js"],
-    acorn: ["assertions.js"],
-    espree: ["assertions.js"],
-    meriyah: ["assertions.js"],
+    flow: ["assertions.js", "template-literal.js", "import-phase.js"],
+    acorn: ["assertions.js", "import-phase.js"],
+    espree: ["assertions.js", "import-phase.js"],
+    meriyah: ["assertions.js", "import-phase.js"],
   },
 });
diff --git a/tests/format/js/dynamic-import/import-phase.js b/tests/format/js/dynamic-import/import-phase.js
new file mode 100644
index 000000000000..fe96b30c4701
--- /dev/null
+++ b/tests/format/js/dynamic-import/import-phase.js
@@ -0,0 +1,7 @@
+import.source(`data:text/javascript,
+    console.log("RUN");
+`)
+
+import.source(String.raw`data:text/javascript,
+    console.log("RUN");
+`)
diff --git a/tests/format/js/dynamic-import/template-literal.js b/tests/format/js/dynamic-import/template-literal.js
new file mode 100644
index 000000000000..bf159aea5176
--- /dev/null
+++ b/tests/format/js/dynamic-import/template-literal.js
@@ -0,0 +1,7 @@
+module   =   await import(`data:text/javascript,
+    console.log("RUN");
+`);
+
+module   =   await import(String.raw`data:text/javascript,
+    console.log("RUN");
+`);