Repository: prettier/prettier (JavaScript)

Issue:
Curly braces and `from` keyword stripped off of `import` statements
**Prettier 2.0.2**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEB6VACA7hATgawGcAdKASwFsAHPGDYAXwwDNcIKMByQ9uGACzJQA5p1Kl0GAEa44AQyKlKNXHWAZUAKgyQKFBHU2Ymrdlx76AtFTlh8c4XDFQJmGfKIYYECEuq16UgwNTABhdn1YUhM2Dm5eDAgBOAwbOwcnEAAaEAgqGDJoQmRQOVw2LAAFMoRilDkANwgyABNskBlbfD4AZTShYWQYXABXOBz+GAoAGwB1QXhCNLge2rIChvWAT2RwQmKcoUI4VUrcBwo5ZGY5aeOcgCtCAA8AIXO7Xrl9ABkhOGut3uICezx6A2mcAAiiMkgCkDc7uMQDZcMdcLspHIpHBpu0qLghDBZq0BMgABwABhyBIgx1m5youwJcHRDQBOQAjrD4Gc8nUQHJCJYoHA4C1xe1ZNyyLIzhcrgigcjjhQyICkTlCBDoTz4cMxjkYNiSS0yUgAExG85kaYDcJ6RUgKDQDkgEbHAAq2LqiOBDTGAEkoBLYD0wIT8gBBEM9GBbSEa44MBhAA)
```sh
--arrow-parens avoid
--parser babel
--no-semi
--single-quote
--trailing-comma none
```

You may wonder what would be the use case for this kind of behavior. It happened to me as I wrote a generator cli for a project creating several files based on user input data and automatically applying a prettier format when those are generated. One of the files provides the empty import statement with the comment in the middle of the curly braces to invite the developer to import what he should from a precise package.

I currently use the first version commented with `// works` in the example to work around the issue.

**Input:**
```jsx
// works
import {} from 'something'

// breaks
import { /* comment */ } from 'some-package'

// breaks too
import {
  // Comment
} from 'some other package'
```

**Output:**
```jsx
// works
import {} from 'something'

// breaks
import /* comment */ 'some-package'

// breaks too
import // Comment
'some other package'

```

**Expected behavior:**
```jsx
// works
import {} from 'something'

// breaks
import { /* comment */ } from 'some-package'

// breaks too
import {
  // Comment
} from 'some other package'

```


Hints:
Strictly speaking, this doesn't break code. Still, better to fix it.
@thorn0 I'm trying to fix this, do you know is there token info in those parser? I can't find anything. We have to use source code? https://github.com/prettier/prettier/blob/aeeb2ff7a8231e2f3a0b2474fd35b4419fe0d97a/src/language-js/printer-estree.js#L1083-L1087

I'm trying to check if it ends with `from`, but might contains comments.

Patch:
diff --git a/src/language-js/print/module.js b/src/language-js/print/module.js
--- a/src/language-js/print/module.js
+++ b/src/language-js/print/module.js
@@ -148,7 +148,7 @@ function printModuleSource(path, options, print) {
 
   /** @type{Doc[]} */
   const parts = [];
-  if (!shouldNotPrintSpecifiers(node, options)) {
+  if (shouldPrintSpecifiers(node, options)) {
     parts.push(" from");
   }
   parts.push(" ", print("source"));
@@ -159,7 +159,7 @@ function printModuleSource(path, options, print) {
 function printModuleSpecifiers(path, options, print) {
   const { node } = path;
 
-  if (shouldNotPrintSpecifiers(node, options)) {
+  if (!shouldPrintSpecifiers(node, options)) {
     return "";
   }
 
@@ -231,21 +231,22 @@ function printModuleSpecifiers(path, options, print) {
   return parts;
 }
 
-function shouldNotPrintSpecifiers(node, options) {
-  const { type, importKind, source, specifiers } = node;
-
+function shouldPrintSpecifiers(node, options) {
   if (
-    type !== "ImportDeclaration" ||
-    isNonEmptyArray(specifiers) ||
-    importKind === "type"
+    node.type !== "ImportDeclaration" ||
+    isNonEmptyArray(node.specifiers) ||
+    node.importKind === "type"
   ) {
-    return false;
+    return true;
   }
 
-  // TODO: check tokens
-  return !/{\s*}/.test(
-    options.originalText.slice(locStart(node), locStart(source)),
+  const text = getTextWithoutComments(
+    options,
+    locStart(node),
+    locStart(node.source),
   );
+
+  return text.trimEnd().endsWith("from");
 }
 
 function getTextWithoutComments(options, start, end) {
@@ -288,8 +289,8 @@ function getImportAttributesOrAssertionsKeyword(node, options) {
 
   const textBetweenSourceAndAttributes = getTextWithoutComments(
     options,
-    node.source.range[1],
-    node.attributes[0].range[0],
+    locEnd(node.source),
+    locStart(node.attributes[0]),
   );
 
   if (textBetweenSourceAndAttributes.trimStart().startsWith("assert")) {


Test patch:
diff --git a/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/js/import/__snapshots__/jsfmt.spec.js.snap
@@ -286,9 +286,92 @@ printWidth: 80
                                                                                 | printWidth
 =====================================input======================================
 import { } from '@types/googlemaps';
+import 'a';
+import /* comment */ 'a';
+import // comment
+'a';
+import { /* comment */ } from 'a';
+import /* comment */ {} from 'a';
+import {} /* comment */ from 'a';
+import {} from /* comment */ 'a';
+import /* comment */ {/* comment */} /* comment */ from /* comment */ 'a';
+import {
+  // comment
+} from 'a';
+import // comment
+{} from 'a';
+import {}
+// comment
+from 'a';
+import {} from
+// comment
+'a';
+import
+// comment
+{
+// comment
+}
+// comment
+from
+// comment
+'a';
+
+import // {} from
+'a';
+import {} from // comment ends with from
+'a';
+import {} from /* comment ends with from */ 'a';
+import {} from // comment not ends with from ___
+'a';
+import {} from /* comment not ends with from ___ */ 'a';
+
+import // comment ends with from
+'a';
+import /* comment ends with from */ 'a';
+import // comment not ends with from ___
+'a';
+import /* comment not ends with from ___ */ 'a';
 
 =====================================output=====================================
 import {} from "@types/googlemaps";
+import "a";
+import /* comment */ "a";
+import // comment
+"a";
+import {} from /* comment */ "a";
+import {} from /* comment */ "a";
+import {} from /* comment */ "a";
+import {} from /* comment */ "a";
+import {} from /* comment */ /* comment */ /* comment */ /* comment */ "a";
+import {} from // comment
+"a";
+import {} from // comment
+"a";
+import {} from // comment
+"a";
+import {} from // comment
+"a";
+import {} from // comment
+// comment
+// comment
+// comment
+"a";
+
+import // {} from
+"a";
+import {} from // comment ends with from
+"a";
+import {} from /* comment ends with from */ "a";
+import {} from // comment not ends with from ___
+"a";
+import {} from /* comment not ends with from ___ */ "a";
+
+import // comment ends with from
+"a";
+import /* comment ends with from */ "a";
+import // comment not ends with from ___
+"a";
+import /* comment not ends with from ___ */ "a";
 
 ================================================================================
 `;
@@ -300,9 +383,92 @@ printWidth: 80
                                                                                 | printWidth
 =====================================input======================================
 import { } from '@types/googlemaps';
+import 'a';
+import /* comment */ 'a';
+import // comment
+'a';
+import { /* comment */ } from 'a';
+import /* comment */ {} from 'a';
+import {} /* comment */ from 'a';
+import {} from /* comment */ 'a';
+import /* comment */ {/* comment */} /* comment */ from /* comment */ 'a';
+import {
+  // comment
+} from 'a';
+import // comment
+{} from 'a';
+import {}
+// comment
+from 'a';
+import {} from
+// comment
+'a';
+import
+// comment
+{
+// comment
+}
+// comment
+from
+// comment
+'a';
+
+import // {} from
+'a';
+import {} from // comment ends with from
+'a';
+import {} from /* comment ends with from */ 'a';
+import {} from // comment not ends with from ___
+'a';
+import {} from /* comment not ends with from ___ */ 'a';
+
+import // comment ends with from
+'a';
+import /* comment ends with from */ 'a';
+import // comment not ends with from ___
+'a';
+import /* comment not ends with from ___ */ 'a';
 
 =====================================output=====================================
 import {} from "@types/googlemaps";
+import "a";
+import /* comment */ "a";
+import // comment
+"a";
+import {} from /* comment */ "a";
+import {} from /* comment */ "a";
+import {} from /* comment */ "a";
+import {} from /* comment */ "a";
+import {} from /* comment */ /* comment */ /* comment */ /* comment */ "a";
+import {} from // comment
+"a";
+import {} from // comment
+"a";
+import {} from // comment
+"a";
+import {} from // comment
+"a";
+import {} from // comment
+// comment
+// comment
+// comment
+"a";
+
+import // {} from
+"a";
+import {} from // comment ends with from
+"a";
+import {} from /* comment ends with from */ "a";
+import {} from // comment not ends with from ___
+"a";
+import {} from /* comment not ends with from ___ */ "a";
+
+import // comment ends with from
+"a";
+import /* comment ends with from */ "a";
+import // comment not ends with from ___
+"a";
+import /* comment not ends with from ___ */ "a";
 
 ================================================================================
 `;
diff --git a/tests/format/js/import/empty-import.js b/tests/format/js/import/empty-import.js
--- a/tests/format/js/import/empty-import.js
+++ b/tests/format/js/import/empty-import.js
@@ -1 +1,46 @@
 import { } from '@types/googlemaps';
+import 'a';
+import /* comment */ 'a';
+import // comment
+'a';
+import { /* comment */ } from 'a';
+import /* comment */ {} from 'a';
+import {} /* comment */ from 'a';
+import {} from /* comment */ 'a';
+import /* comment */ {/* comment */} /* comment */ from /* comment */ 'a';
+import {
+  // comment
+} from 'a';
+import // comment
+{} from 'a';
+import {}
+// comment
+from 'a';
+import {} from
+// comment
+'a';
+import
+// comment
+{
+// comment
+}
+// comment
+from
+// comment
+'a';
+
+import // {} from
+'a';
+import {} from // comment ends with from
+'a';
+import {} from /* comment ends with from */ 'a';
+import {} from // comment not ends with from ___
+'a';
+import {} from /* comment not ends with from ___ */ 'a';
+
+import // comment ends with from
+'a';
+import /* comment ends with from */ 'a';
+import // comment not ends with from ___
+'a';
+import /* comment not ends with from ___ */ 'a';
diff --git a/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/typescript/import-export/__snapshots__/jsfmt.spec.js.snap
@@ -1,5 +1,102 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`empty-import.ts format 1`] = `
+====================================options=====================================
+parsers: ["typescript"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+import type { } from '@types/googlemaps';
+import 'a';
+import /* comment */ 'a';
+import // comment
+'a';
+import type { /* comment */ } from 'a';
+import /* comment */ type {} from 'a';
+import type {} /* comment */ from 'a';
+import type {} from /* comment */ 'a';
+import /* comment */ type {/* comment */} /* comment */ from /* comment */ 'a';
+import type {
+  // comment
+} from 'a';
+import // comment
+type {} from 'a';
+import type {}
+// comment
+from 'a';
+import type {} from
+// comment
+'a';
+import type
+// comment
+{
+// comment
+}
+// comment
+from
+// comment
+'a';
+
+import // {} from
+'a';
+import  type {} from // comment ends with from
+'a';
+import type {} from /* comment ends with from */ 'a';
+import type {} from // comment not ends with from ___
+'a';
+import type {} from /* comment not ends with from ___ */ 'a';
+
+import // comment ends with from
+'a';
+import /* comment ends with from */ 'a';
+import // comment not ends with from ___
+'a';
+import /* comment not ends with from ___ */ 'a';
+
+=====================================output=====================================
+import type {} from "@types/googlemaps";
+import "a";
+import /* comment */ "a";
+import // comment
+"a";
+import type {} from /* comment */ "a";
+import type {} from /* comment */ "a";
+import type {} from /* comment */ "a";
+import type {} from /* comment */ "a";
+import type {} from /* comment */ /* comment */ /* comment */ /* comment */ "a";
+import type {} from // comment
+"a";
+import type {} from // comment
+"a";
+import type {} from // comment
+"a";
+import type {} from // comment
+"a";
+import type {} from // comment
+// comment
+// comment
+// comment
+"a";
+
+import // {} from
+"a";
+import type {} from // comment ends with from
+"a";
+import type {} from /* comment ends with from */ "a";
+import type {} from // comment not ends with from ___
+"a";
+import type {} from /* comment not ends with from ___ */ "a";
+
+import // comment ends with from
+"a";
+import /* comment ends with from */ "a";
+import // comment not ends with from ___
+"a";
+import /* comment not ends with from ___ */ "a";
+
+================================================================================
+`;
+
 exports[`type-modifier.ts format 1`] = `
 ====================================options=====================================
 parsers: ["typescript"]
diff --git a/tests/format/typescript/import-export/empty-import.ts b/tests/format/typescript/import-export/empty-import.ts
new file mode 100644
--- /dev/null
+++ b/tests/format/typescript/import-export/empty-import.ts
@@ -0,0 +1,46 @@
+import type { } from '@types/googlemaps';
+import 'a';
+import /* comment */ 'a';
+import // comment
+'a';
+import type { /* comment */ } from 'a';
+import /* comment */ type {} from 'a';
+import type {} /* comment */ from 'a';
+import type {} from /* comment */ 'a';
+import /* comment */ type {/* comment */} /* comment */ from /* comment */ 'a';
+import type {
+  // comment
+} from 'a';
+import // comment
+type {} from 'a';
+import type {}
+// comment
+from 'a';
+import type {} from
+// comment
+'a';
+import type
+// comment
+{
+// comment
+}
+// comment
+from
+// comment
+'a';
+
+import // {} from
+'a';
+import  type {} from // comment ends with from
+'a';
+import type {} from /* comment ends with from */ 'a';
+import type {} from // comment not ends with from ___
+'a';
+import type {} from /* comment not ends with from ___ */ 'a';
+
+import // comment ends with from
+'a';
+import /* comment ends with from */ 'a';
+import // comment not ends with from ___
+'a';
+import /* comment not ends with from ___ */ 'a';