Repository: babel/babel (TypeScript)

Issue:
[Bug]: Regression. Babel generates invalid code.
### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

babel-loader (webpack)

### Input code

```js
import { apiLogout } from "../api";
import { reportError } from "../libs/report_error";

export function logout() {
  return reportError(async (/*dispatch*/) => {
    await apiLogout();
    window.location.reload();
  });
}
```


### Configuration file name

babel.config.js

### Configuration

```js
module.exports = function(api) {
  const isTest = api.env('test');

  const envOptions = isTest
    ? {
      "targets": {
        "node": "current"
      }
    }
    : {
      modules: false,
      useBuiltIns: 'usage',
      corejs: "3.25",
      // debug: true,
    };

  return {
    "presets": [
      ["@babel/preset-env", envOptions],
      "@babel/preset-react"
    ],
  };
};
```

### Current and expected behavior

After an upgrade from `7.19.3` to `7.19.6` I've got a following failure.

```
ERROR in ./assets/actions/user.js 12:5
Module parse failed: Unexpected token (12:5)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| export function logout() {
|   return reportError(async /*dispatch*/
>   () => {
|     await apiLogout();
|     window.location.reload();
 @ ./assets/actions/index.js 2:0-37 12:13-24
 @ ./assets/app.js 6:0-37 12:15-23
```

Babel inserts a new line and breaks async closure (I guess, auto-insertion of semicolon is involved).

The same error is reproducible in an online playground with other versions: [7.17.12 generates correct code](https://babel.dev/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=JYWwDg9gTgLgBAbzgQzMAMhA5hArvAXzgDMoIQ4AiAOmoHpVhKBuAKFElkTigFNOYAUShkocIqXJVadADbAARgGc6fAQH1eI6C1ateADwElcAOwDGMYBFNxZ2PDAAUASkSs4PXjFxRba6CFtKCdkJQBPCzgnOgAqABNgJTBkGHMAC1i6NwBeAD53T09kAHdkYHhGTBx8VzYiuBLgU3iIEup7c1TrU2o-e2R4uo9xFzYCViA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact&prettier=false&targets=&version=7.17.12&externalPlugins=&assumptions=%7B%7D) while [7.20.1 generates invalid code](https://babel.dev/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=JYWwDg9gTgLgBAbzgQzMAMhA5hArvAXzgDMoIQ4AiAOmoHpVhKBuAKFElkTigFNOYAUShkocIqXJVadADbAARgGc6fAQH1eI6C1ateADwElcAOwDGMYBFNxZ2PDAAUASkSs4PXjFxRba6CFtKCdkJQBPCzgnOgAqABNgJTBkGHMAC1i6NwBeAD53T09kAHdkYHhGTBx8VzYiuBLgU3iIEup7c1TrU2o-e2R4uo9xFzYCViA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact&prettier=false&targets=&version=7.20.1&externalPlugins=&assumptions=%7B%7D)



### Environment

#### Environment w/o the issue

  System:
    OS: Linux 6.0 Debian GNU/Linux bookworm/sid
  Binaries:
    Node: 14.20.0 - ~/apps/nodejs/bin/node
    Yarn: 1.22.19 - ~/apps/nodejs/bin/yarn
    npm: 6.14.17 - ~/apps/nodejs/bin/npm
  npmPackages:
    @babel/core: ^7 => 7.19.3 
    @babel/eslint-parser: ^7 => 7.19.1 
    @babel/preset-env: ^7 => 7.19.3 
    @babel/preset-react: ^7 => 7.18.6 
    babel-jest: ^29 => 29.1.2 
    babel-loader: ^8.0.0 => 8.2.5 
    eslint: ^8.2 => 8.24.0 
    jest: ^29 => 29.1.2 
    webpack: ^5 => 5.74.0 

#### Environment with the issue (after `yarn upgrade`)

  System:
    OS: Linux 6.0 Debian GNU/Linux bookworm/sid
  Binaries:
    Node: 14.20.0 - ~/apps/nodejs/bin/node
    Yarn: 1.22.19 - ~/apps/nodejs/bin/yarn
    npm: 6.14.17 - ~/apps/nodejs/bin/npm
  npmPackages:
    @babel/core: ^7 => 7.19.6 
    @babel/eslint-parser: ^7 => 7.19.1 
    @babel/preset-env: ^7 => 7.19.4 
    @babel/preset-react: ^7 => 7.18.6 
    babel-jest: ^29 => 29.2.2 
    babel-loader: ^8.0.0 => 8.2.5 
    eslint: ^8.2 => 8.26.0 
    jest: ^29 => 29.2.2 
    webpack: ^5 => 5.74.0 


### Possible solution

_No response_

### Additional context

_No response_


Hints:
Hey @andy128k! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/) for an invite.
Introduced by https://github.com/babel/babel/pull/15080, I'll work on a fix.

Patch:
diff --git a/packages/babel-generator/src/generators/classes.ts b/packages/babel-generator/src/generators/classes.ts
--- a/packages/babel-generator/src/generators/classes.ts
+++ b/packages/babel-generator/src/generators/classes.ts
@@ -134,7 +134,7 @@ export function ClassAccessorProperty(
   // TS does not support class accessor property yet
   this.tsPrintClassMemberModifiers(node);
 
-  this.word("accessor");
+  this.word("accessor", true);
   this.space();
 
   if (node.computed) {
diff --git a/packages/babel-generator/src/generators/expressions.ts b/packages/babel-generator/src/generators/expressions.ts
--- a/packages/babel-generator/src/generators/expressions.ts
+++ b/packages/babel-generator/src/generators/expressions.ts
@@ -26,14 +26,11 @@ export function UnaryExpression(this: Printer, node: t.UnaryExpression) {
 }
 
 export function DoExpression(this: Printer, node: t.DoExpression) {
-  // ensure no line terminator between `async` and `do`
-  this.ensureNoLineTerminator(() => {
-    if (node.async) {
-      this.word("async");
-      this.space();
-    }
-    this.word("do");
-  });
+  if (node.async) {
+    this.word("async", true);
+    this.space();
+  }
+  this.word("do");
   this.space();
   this.print(node.body, node);
 }
@@ -230,12 +227,10 @@ export function AwaitExpression(this: Printer, node: t.AwaitExpression) {
 }
 
 export function YieldExpression(this: Printer, node: t.YieldExpression) {
-  this.word("yield");
+  this.word("yield", true);
 
   if (node.delegate) {
-    this.ensureNoLineTerminator(() => {
-      this.token("*");
-    });
+    this.token("*");
     if (node.argument) {
       this.space();
       // line terminators are allowed after yield*
@@ -360,12 +355,9 @@ export function V8IntrinsicIdentifier(
 }
 
 export function ModuleExpression(this: Printer, node: t.ModuleExpression) {
-  this.word("module");
+  this.word("module", true);
   this.space();
-  // ensure no line terminator between `module` and `{`
-  this.ensureNoLineTerminator(() => {
-    this.token("{");
-  });
+  this.token("{");
   this.indent();
   const { body } = node;
   if (body.body.length || body.directives.length) {
diff --git a/packages/babel-generator/src/generators/methods.ts b/packages/babel-generator/src/generators/methods.ts
--- a/packages/babel-generator/src/generators/methods.ts
+++ b/packages/babel-generator/src/generators/methods.ts
@@ -10,6 +10,7 @@ export function _params(
   this.token("(");
   this._parameters(node.params, node);
   this.token(")");
+  this._noLineTerminator = true;
 
   this.print(node.returnType, node, node.type === "ArrowFunctionExpression");
 }
@@ -72,11 +73,8 @@ export function _methodHead(this: Printer, node: t.Method | t.TSDeclareMethod) {
     this.space();
   }
 
-  const { _noLineTerminator } = this;
   if (node.async) {
-    // ensure no line terminator between async and class element name / *
-    this._noLineTerminator = true;
-    this.word("async");
+    this.word("async", true);
     this.space();
   }
 
@@ -87,18 +85,15 @@ export function _methodHead(this: Printer, node: t.Method | t.TSDeclareMethod) {
   ) {
     if (node.generator) {
       this.token("*");
-      this._noLineTerminator = _noLineTerminator;
     }
   }
 
   if (node.computed) {
     this.token("[");
-    this._noLineTerminator = _noLineTerminator;
     this.print(key, node);
     this.token("]");
   } else {
     this.print(key, node);
-    this._noLineTerminator = _noLineTerminator;
   }
 
   if (
@@ -118,13 +113,14 @@ export function _predicate(
     | t.FunctionDeclaration
     | t.FunctionExpression
     | t.ArrowFunctionExpression,
+  noLineTerminatorAfter?: boolean,
 ) {
   if (node.predicate) {
     if (!node.returnType) {
       this.token(":");
     }
     this.space();
-    this.print(node.predicate, node);
+    this.print(node.predicate, node, noLineTerminatorAfter);
   }
 }
 
@@ -172,10 +168,8 @@ export function ArrowFunctionExpression(
   this: Printer,
   node: t.ArrowFunctionExpression,
 ) {
-  const { _noLineTerminator } = this;
   if (node.async) {
-    this._noLineTerminator = true;
-    this.word("async");
+    this.word("async", true);
     this.space();
   }
 
@@ -188,22 +182,18 @@ export function ArrowFunctionExpression(
     isIdentifier((firstParam = node.params[0])) &&
     !hasTypesOrComments(node, firstParam)
   ) {
-    this.print(firstParam, node);
-    this._noLineTerminator = _noLineTerminator;
+    this.print(firstParam, node, true);
   } else {
-    this._noLineTerminator = _noLineTerminator;
     this._params(node);
   }
 
-  this._predicate(node);
-  this.ensureNoLineTerminator(() => {
-    this.space();
-    // When printing (x)/*1*/=>{}, we remove the parentheses
-    // and thus there aren't two contiguous inner tokens.
-    // We forcefully print inner comments here.
-    this.printInnerComments();
-    this.token("=>");
-  });
+  this._predicate(node, true);
+  this.space();
+  // When printing (x)/*1*/=>{}, we remove the parentheses
+  // and thus there aren't two contiguous inner tokens.
+  // We forcefully print inner comments here.
+  this.printInnerComments();
+  this.token("=>");
 
   this.space();
 
diff --git a/packages/babel-generator/src/generators/modules.ts b/packages/babel-generator/src/generators/modules.ts
--- a/packages/babel-generator/src/generators/modules.ts
+++ b/packages/babel-generator/src/generators/modules.ts
@@ -70,6 +70,7 @@ export function _printAssertions(
   this: Printer,
   node: Extract<t.Node, { assertions?: t.ImportAttribute[] }>,
 ) {
+  this.word("assert");
   this.space();
   this.token("{");
   this.space();
@@ -94,11 +95,8 @@ export function ExportAllDeclaration(
   this.space();
   // @ts-expect-error Fixme: assertions is not defined in DeclareExportAllDeclaration
   if (node.assertions?.length) {
-    this.ensureNoLineTerminator(() => {
-      this.print(node.source, node);
-      this.space();
-      this.word("assert");
-    });
+    this.print(node.source, node, true);
+    this.space();
     // @ts-expect-error Fixme: assertions is not defined in DeclareExportAllDeclaration
     this._printAssertions(node);
   } else {
@@ -169,11 +167,8 @@ export function ExportNamedDeclaration(
       this.word("from");
       this.space();
       if (node.assertions?.length) {
-        this.ensureNoLineTerminator(() => {
-          this.print(node.source, node);
-          this.space();
-          this.word("assert");
-        });
+        this.print(node.source, node, true);
+        this.space();
         this._printAssertions(node);
       } else {
         this.print(node.source, node);
@@ -258,10 +253,7 @@ export function ImportDeclaration(this: Printer, node: t.ImportDeclaration) {
 
   if (node.assertions?.length) {
     this.print(node.source, node, true);
-    this.ensureNoLineTerminator(() => {
-      this.space();
-      this.word("assert");
-    });
+    this.space();
     this._printAssertions(node);
   } else {
     this.print(node.source, node);
diff --git a/packages/babel-generator/src/generators/statements.ts b/packages/babel-generator/src/generators/statements.ts
--- a/packages/babel-generator/src/generators/statements.ts
+++ b/packages/babel-generator/src/generators/statements.ts
@@ -1,5 +1,4 @@
 import type Printer from "../printer";
-import type { PrintJoinOptions } from "../printer";
 import {
   isFor,
   isForStatement,
@@ -262,12 +261,7 @@ export function VariableDeclaration(
   }
 
   const { kind } = node;
-  this.word(kind);
-  const { _noLineTerminator } = this;
-  if (kind === "using") {
-    // ensure no line break after `using`
-    this._noLineTerminator = true;
-  }
+  this.word(kind, kind === "using");
   this.space();
 
   let hasInits = false;
@@ -293,16 +287,6 @@ export function VariableDeclaration(
   //       bar = "foo";
   //
 
-  let iterator: PrintJoinOptions["iterator"] | undefined;
-  if (kind === "using") {
-    // Ensure no line break between `using` and the first declarator
-    iterator = (_, i: number) => {
-      if (i === 0) {
-        this._noLineTerminator = _noLineTerminator;
-      }
-    };
-  }
-
   this.printList(node.declarations, node, {
     separator: hasInits
       ? function (this: Printer) {
@@ -310,7 +294,6 @@ export function VariableDeclaration(
           this.newline();
         }
       : undefined,
-    iterator,
     indent: node.declarations.length > 1 ? true : false,
   });
 
diff --git a/packages/babel-generator/src/printer.ts b/packages/babel-generator/src/printer.ts
--- a/packages/babel-generator/src/printer.ts
+++ b/packages/babel-generator/src/printer.ts
@@ -22,6 +22,7 @@ const SCIENTIFIC_NOTATION = /e/i;
 const ZERO_DECIMAL_INTEGER = /\.0+$/;
 const NON_DECIMAL_LITERAL = /^0[box]/;
 const PURE_ANNOTATION_RE = /^\s*[@#]__PURE__\s*$/;
+const HAS_NEWLINE = /[\n\r\u2028\u2029]/;
 
 const { needsParens } = n;
 
@@ -151,6 +152,7 @@ class Printer {
     } else {
       this._queue(charCodes.semicolon);
     }
+    this._noLineTerminator = false;
   }
 
   /**
@@ -185,7 +187,7 @@ class Printer {
    * Writes a token that can't be safely parsed without taking whitespace into account.
    */
 
-  word(str: string): void {
+  word(str: string, noLineTerminatorAfter: boolean = false): void {
     this._maybePrintInnerComments();
 
     // prevent concatenating words and creating // comment out of division and regex
@@ -200,6 +202,7 @@ class Printer {
     this._append(str, false);
 
     this._endsWithWord = true;
+    this._noLineTerminator = noLineTerminatorAfter;
   }
 
   /**
@@ -243,6 +246,7 @@ class Printer {
 
     this._maybeAddAuxComment();
     this._append(str, maybeNewline);
+    this._noLineTerminator = false;
   }
 
   tokenChar(char: number): void {
@@ -263,6 +267,7 @@ class Printer {
 
     this._maybeAddAuxComment();
     this._appendChar(char);
+    this._noLineTerminator = false;
   }
 
   /**
@@ -534,13 +539,6 @@ class Printer {
     return this._indentRepeat * this._indent;
   }
 
-  ensureNoLineTerminator(fn: () => void) {
-    const { _noLineTerminator } = this;
-    this._noLineTerminator = true;
-    fn();
-    this._noLineTerminator = _noLineTerminator;
-  }
-
   printTerminatorless(node: t.Node, parent: t.Node, isLabel: boolean) {
     /**
      * Set some state that will be modified if a newline has been inserted before any
@@ -558,9 +556,8 @@ class Printer {
      *  `undefined` will be returned and not `foo` due to the terminator.
      */
     if (isLabel) {
-      this.ensureNoLineTerminator(() => {
-        this.print(node, parent);
-      });
+      this._noLineTerminator = true;
+      this.print(node, parent);
     } else {
       const terminatorState = {
         printed: false,
@@ -581,9 +578,9 @@ class Printer {
   print(
     node: t.Node | null,
     parent?: t.Node,
-    noLineTerminator?: boolean,
+    noLineTerminatorAfter?: boolean,
     // trailingCommentsLineOffset also used to check if called from printJoin
-    // it will be ignored if `noLineTerminator||this._noLineTerminator`
+    // it will be ignored if `noLineTerminatorAfter||this._noLineTerminator`
     trailingCommentsLineOffset?: number,
     forceParens?: boolean,
   ) {
@@ -649,16 +646,17 @@ class Printer {
 
     this.exactSource(loc, printMethod.bind(this, node, parent));
 
-    if (noLineTerminator && !this._noLineTerminator) {
+    if (shouldPrintParens) {
+      this._printTrailingComments(node, parent);
+      this.token(")");
+      this._noLineTerminator = noLineTerminatorAfter;
+    } else if (noLineTerminatorAfter && !this._noLineTerminator) {
       this._noLineTerminator = true;
       this._printTrailingComments(node, parent);
-      this._noLineTerminator = false;
     } else {
       this._printTrailingComments(node, parent, trailingCommentsLineOffset);
     }
 
-    if (shouldPrintParens) this.token(")");
-
     // end
     this._printStack.pop();
 
@@ -891,14 +889,26 @@ class Printer {
     }
   }
 
-  _printComment(comment: t.Comment, skipNewLines: COMMENT_SKIP_NEWLINE): void {
+  // Returns `true` if the comment cannot be printed in this position due to
+  // line terminators, signaling that the print comments loop can stop and
+  // resume printing comments at the next posisble position. This happens when
+  // printing inner comments, since if we have an inner comment with a multiline
+  // there is at least one inner position where line terminators are allowed.
+  _printComment(
+    comment: t.Comment,
+    skipNewLines: COMMENT_SKIP_NEWLINE,
+  ): boolean {
     // Some plugins (such as flow-strip-types) use this to mark comments as removed using the AST-root 'comments' property,
     // where they can't manually mutate the AST node comment lists.
-    if (comment.ignore) return;
+    if (comment.ignore) return false;
 
-    if (this._printedComments.has(comment)) return;
+    if (this._printedComments.has(comment)) return false;
 
-    if (!this.format.shouldPrintComment(comment.value)) return;
+    if (this._noLineTerminator && HAS_NEWLINE.test(comment.value)) {
+      return true;
+    }
+
+    if (!this.format.shouldPrintComment(comment.value)) return false;
 
     this._printedComments.add(comment);
 
@@ -950,6 +960,9 @@ class Printer {
     } else if (!this._noLineTerminator) {
       val = `//${comment.value}`;
     } else {
+      // It was a single-line comment, so it's guaranteed to not
+      // contain newlines and it can be safely printed as a block
+      // comment.
       val = `/*${comment.value}*/`;
     }
 
@@ -966,6 +979,8 @@ class Printer {
     if (printNewLines && skipNewLines !== COMMENT_SKIP_NEWLINE.SKIP_TRAILING) {
       this.newline(1);
     }
+
+    return false;
   }
 
   _printComments(
@@ -975,123 +990,124 @@ class Printer {
     parent?: t.Node,
     lineOffset: number = 0,
   ) {
-    {
-      const nodeLoc = node.loc;
-      const len = comments.length;
-      let hasLoc = !!nodeLoc;
-      const nodeStartLine = hasLoc ? nodeLoc.start.line : 0;
-      const nodeEndLine = hasLoc ? nodeLoc.end.line : 0;
-      let lastLine = 0;
-      let leadingCommentNewline = 0;
-
-      for (let i = 0; i < len; i++) {
-        const comment = comments[i];
-
-        if (hasLoc && comment.loc && !this._printedComments.has(comment)) {
-          const commentStartLine = comment.loc.start.line;
-          const commentEndLine = comment.loc.end.line;
-          if (type === COMMENT_TYPE.LEADING) {
-            let offset = 0;
-            if (i === 0) {
-              // Because currently we cannot handle blank lines before leading comments,
-              // we always wrap before and after multi-line comments.
-              if (
-                this._buf.hasContent() &&
-                (comment.type === "CommentLine" ||
-                  commentStartLine != commentEndLine)
-              ) {
-                offset = leadingCommentNewline = 1;
-              }
-            } else {
-              offset = commentStartLine - lastLine;
-            }
-            lastLine = commentEndLine;
-
-            this.newline(offset);
-            this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL);
+    const nodeLoc = node.loc;
+    const len = comments.length;
+    let hasLoc = !!nodeLoc;
+    const nodeStartLine = hasLoc ? nodeLoc.start.line : 0;
+    const nodeEndLine = hasLoc ? nodeLoc.end.line : 0;
+    let lastLine = 0;
+    let leadingCommentNewline = 0;
+    const { _noLineTerminator } = this;
 
-            if (i + 1 === len) {
-              this.newline(
-                Math.max(nodeStartLine - lastLine, leadingCommentNewline),
-              );
-              lastLine = nodeStartLine;
+    for (let i = 0; i < len; i++) {
+      const comment = comments[i];
+
+      if (hasLoc && comment.loc && !this._printedComments.has(comment)) {
+        const commentStartLine = comment.loc.start.line;
+        const commentEndLine = comment.loc.end.line;
+        if (type === COMMENT_TYPE.LEADING) {
+          let offset = 0;
+          if (i === 0) {
+            // Because currently we cannot handle blank lines before leading comments,
+            // we always wrap before and after multi-line comments.
+            if (
+              this._buf.hasContent() &&
+              (comment.type === "CommentLine" ||
+                commentStartLine != commentEndLine)
+            ) {
+              offset = leadingCommentNewline = 1;
             }
-          } else if (type === COMMENT_TYPE.INNER) {
-            const offset =
-              commentStartLine - (i === 0 ? nodeStartLine : lastLine);
-            lastLine = commentEndLine;
+          } else {
+            offset = commentStartLine - lastLine;
+          }
+          lastLine = commentEndLine;
 
-            this.newline(offset);
-            this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL);
+          if (!_noLineTerminator) this.newline(offset);
+          this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL);
 
-            if (i + 1 === len) {
-              this.newline(Math.min(1, nodeEndLine - lastLine)); // TODO: Improve here when inner comments processing is stronger
-              lastLine = nodeEndLine;
-            }
-          } else {
-            const offset =
-              commentStartLine -
-              (i === 0 ? nodeEndLine - lineOffset : lastLine);
-            lastLine = commentEndLine;
+          if (!_noLineTerminator && i + 1 === len) {
+            this.newline(
+              Math.max(nodeStartLine - lastLine, leadingCommentNewline),
+            );
+            lastLine = nodeStartLine;
+          }
+        } else if (type === COMMENT_TYPE.INNER) {
+          const offset =
+            commentStartLine - (i === 0 ? nodeStartLine : lastLine);
+          lastLine = commentEndLine;
+
+          if (!_noLineTerminator) this.newline(offset);
+          if (this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL)) break;
 
-            this.newline(offset);
-            this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL);
+          if (!_noLineTerminator && i + 1 === len) {
+            this.newline(Math.min(1, nodeEndLine - lastLine)); // TODO: Improve here when inner comments processing is stronger
+            lastLine = nodeEndLine;
           }
         } else {
-          hasLoc = false;
-
-          if (len === 1) {
-            const singleLine = comment.loc
-              ? comment.loc.start.line === comment.loc.end.line
-              : !comment.value.includes("\n");
-
-            const shouldSkipNewline =
-              singleLine &&
-              !isStatement(node) &&
-              !isClassBody(parent) &&
-              !isTSInterfaceBody(parent);
-
-            if (type === COMMENT_TYPE.LEADING) {
-              this._printComment(
-                comment,
-                (shouldSkipNewline && node.type !== "ObjectExpression") ||
-                  (singleLine && isFunction(parent, { body: node }))
-                  ? COMMENT_SKIP_NEWLINE.SKIP_ALL
-                  : COMMENT_SKIP_NEWLINE.DEFAULT,
-              );
-            } else if (shouldSkipNewline && type === COMMENT_TYPE.TRAILING) {
-              this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL);
-            } else {
-              this._printComment(comment, COMMENT_SKIP_NEWLINE.DEFAULT);
-            }
-          } else if (
-            type === COMMENT_TYPE.INNER &&
-            !(node.type === "ObjectExpression" && node.properties.length > 1) &&
-            node.type !== "ClassBody" &&
-            node.type !== "TSInterfaceBody"
-          ) {
-            // class X {
-            //   /*:: a: number*/
-            //   /*:: b: ?string*/
-            // }
+          const offset =
+            commentStartLine - (i === 0 ? nodeEndLine - lineOffset : lastLine);
+          lastLine = commentEndLine;
+
+          if (!_noLineTerminator) this.newline(offset);
+          this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL);
+        }
+      } else {
+        hasLoc = false;
+
+        if (len === 1) {
+          const singleLine = comment.loc
+            ? comment.loc.start.line === comment.loc.end.line
+            : !comment.value.includes("\n");
 
+          const shouldSkipNewline =
+            singleLine &&
+            !isStatement(node) &&
+            !isClassBody(parent) &&
+            !isTSInterfaceBody(parent);
+
+          if (type === COMMENT_TYPE.LEADING) {
             this._printComment(
               comment,
-              i === 0
-                ? COMMENT_SKIP_NEWLINE.SKIP_LEADING
-                : i === len - 1
-                ? COMMENT_SKIP_NEWLINE.SKIP_TRAILING
+              (shouldSkipNewline && node.type !== "ObjectExpression") ||
+                (singleLine && isFunction(parent, { body: node }))
+                ? COMMENT_SKIP_NEWLINE.SKIP_ALL
                 : COMMENT_SKIP_NEWLINE.DEFAULT,
             );
+          } else if (shouldSkipNewline && type === COMMENT_TYPE.TRAILING) {
+            if (this._printComment(comment, COMMENT_SKIP_NEWLINE.SKIP_ALL)) {
+              break;
+            }
           } else {
             this._printComment(comment, COMMENT_SKIP_NEWLINE.DEFAULT);
           }
+        } else if (
+          type === COMMENT_TYPE.INNER &&
+          !(node.type === "ObjectExpression" && node.properties.length > 1) &&
+          node.type !== "ClassBody" &&
+          node.type !== "TSInterfaceBody"
+        ) {
+          // class X {
+          //   /*:: a: number*/
+          //   /*:: b: ?string*/
+          // }
+
+          const skippedDueToNewlie = this._printComment(
+            comment,
+            i === 0
+              ? COMMENT_SKIP_NEWLINE.SKIP_LEADING
+              : i === len - 1
+              ? COMMENT_SKIP_NEWLINE.SKIP_TRAILING
+              : COMMENT_SKIP_NEWLINE.DEFAULT,
+          );
+          if (skippedDueToNewlie) break;
+        } else {
+          this._printComment(comment, COMMENT_SKIP_NEWLINE.DEFAULT);
         }
       }
+    }
 
-      if (type === COMMENT_TYPE.TRAILING && hasLoc && lastLine) {
-        this._lastCommentLine = lastLine;
-      }
+    if (type === COMMENT_TYPE.TRAILING && hasLoc && lastLine) {
+      this._lastCommentLine = lastLine;
     }
   }
 }


Test patch:
diff --git a/packages/babel-generator/test/fixtures/decorator-auto-accessors/comments/input.js b/packages/babel-generator/test/fixtures/decorator-auto-accessors/comments/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-generator/test/fixtures/decorator-auto-accessors/comments/input.js
@@ -0,0 +1,6 @@
+class A {
+  /* 0 */ accessor /* 1 */ x /* 2 */ = /* 3 */ 0 /* 4 */; /* 5 */
+
+  /* 6 */ accessor /* 7 */ [/* 8 */ x /* 9 */] /* 10
+  multiline */ = /* 11 */ 0 /* 12 */; /* 13 */
+}
diff --git a/packages/babel-generator/test/fixtures/decorator-auto-accessors/comments/output.js b/packages/babel-generator/test/fixtures/decorator-auto-accessors/comments/output.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-generator/test/fixtures/decorator-auto-accessors/comments/output.js
@@ -0,0 +1,8 @@
+class A {
+  /* 0 */accessor /* 1 */x /* 2 */ = /* 3 */0 /* 4 */; /* 5 */
+
+  /* 6 */
+  accessor /* 7 */ [/* 8 */x /* 9 */]
+    /* 10
+    multiline */ = /* 11 */0 /* 12 */; /* 13 */
+}
\ No newline at end of file
diff --git a/packages/babel-generator/test/fixtures/decorator-auto-accessors/options.json b/packages/babel-generator/test/fixtures/decorator-auto-accessors/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-generator/test/fixtures/decorator-auto-accessors/options.json
@@ -0,0 +1,7 @@
+{
+  "plugins": [
+    ["decorators", { "decoratorsBeforeExport": false }],
+    "decoratorAutoAccessors"
+  ],
+  "decoratorsBeforeExport": true
+}
diff --git a/packages/babel-generator/test/fixtures/regression/inner-comment-async-arrows/input.js b/packages/babel-generator/test/fixtures/regression/inner-comment-async-arrows/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-generator/test/fixtures/regression/inner-comment-async-arrows/input.js
@@ -0,0 +1,14 @@
+async /* 1 */ () => {};
+async () /* 2 */ => {};
+async /* 3 */ (param) => {};
+async (param) /* 4 */ => {};
+async ( /* 5 */ ) => {};
+async ( /*
+         * 6 with newline
+         */
+) => {};
+
+async /* 7 */ ( /*
+                 * 8 with newline
+                 */
+) /* 9 */ => {};
\ No newline at end of file
diff --git a/packages/babel-generator/test/fixtures/regression/inner-comment-async-arrows/output.js b/packages/babel-generator/test/fixtures/regression/inner-comment-async-arrows/output.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-generator/test/fixtures/regression/inner-comment-async-arrows/output.js
@@ -0,0 +1,14 @@
+async /* 1 */ () => {};
+async /* 2 */ () => {};
+async param /* 3 */ => {};
+async param /* 4 */ => {};
+async /* 5 */ () => {};
+async ( /*
+         * 6 with newline
+         */
+) => {};
+async /* 7 */ (
+  /*
+   * 8 with newline
+   */
+  /* 9 */) => {};
\ No newline at end of file