Repository: babel/babel (TypeScript)

Issue:
[Bug]: super operator call using ternary operator
### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

@babel/cli

### Input code

7.20.15 - [Babel REPL](https://babel.dev/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=false&spec=false&loose=false&code_lz=G4QwTgBASgrgNgUwMIHsB2AXBAPDEC8EAxnCAM5kQDeEAUBBAJZrAoDWzA5gMoYhYBuesXRkMYGEQwowACgAO4BJgA0TFuy69-CAJTVhDDAAtGZAHSKwyvISs2IAfkcQ08OEIZHTF5qw5oPHxYBOr-WsEITi4AtACMnhAAvrQpDLSgkAAK4GQIYLCIqJg4tsSkFBAA-jlgeQXwyOhYuBClygAmlIVNJa1UwmLgZW5wHoPS8qGj4ww4RAjyGIzo0-6JRKLiktJyCGoY-gNeEAD0pwiOZDDy-bL7hwBc17dyuiomZuZDYCPuHz5vpM1mNDGcAFSMABmEHuumOJwgLzuD10iQYSTacDyBhOAEhkW90clwacwZdCfcProwRBnjc7mjhCkUhlwBApoQ0AgAO4QWr1HrFFoYWRooA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&timeTravel=false&sourceType=unambiguous&lineWrap=false&presets=env&prettier=false&targets=&version=7.20.15&externalPlugins=&assumptions=%7B%7D)

latest + force all transform - [Babel REPL](https://babel.dev/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=false&spec=false&loose=false&code_lz=G4QwTgBASgrgNgUwMIHsB2AXBAPDEC8EAxnCAM5kQDeEAUBBAJZrAoDWzA5gMoYhYBuesXRkMYGEQwowACgAO4BJgA0TFuy69-CAJTVhDDAAtGZAHSKwyvISs2IAfkcQ08OEIZHTF5qw5oPHxYBOr-WsEITi4AtACMnhAAvrQpDLSgkAAK4GQIYLCIqJg4tsSkFBAA-jlgeQXwyOhYuBClygAmlIVNJa1UwmLgZW5wHoPS8qGj4ww4RAjyGIzo0-6JRKLiktJyCGoY-gNeEAD0pwiOZDDy-bL7hwBc17dyuiomZuZDYCPuHz5vpM1mNDGcAFSMABmEHuumOJwgLzuD10iQYSTacDyBhOAEhkW90clwacwZdCfcProwRBnjc7mjhCkUhlwBApoQ0AgAO4QWr1HrFFoYWRooA&debug=false&forceAllTransforms=true&modules=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&timeTravel=false&sourceType=unambiguous&lineWrap=false&presets=env&prettier=false&targets=&version=7.23.4&externalPlugins=&assumptions=%7B%7D)

### Configuration file name

_No response_

### Configuration

see conf in REPL example

### Current and expected behavior

**Current behavior**:
v7.20.5/7.21.9: throw exception in runtime  - *Super constructor may only be called once*
latest + force all transform : no exception but generates super call same way

It works fine, when use "if else" instead ternary - [example](https://babel.dev/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=false&spec=false&loose=false&code_lz=G4QwTgBASgrgNgUwMIHsB2AXBAPDEC8EAxnCAM5kQDeEAUBBAJZrAoDWzA5gMoYhYBuesXRkMYGEQwowACgAO4BJgA0TFuy69-CAJTVhDDAAtGZAHSKwyvISs2IAfkcQ08OEIZHTF5qw5oPHxYBOr-WsEITi4AtACMnhAAvrQpDLSgkAAK4GQIYLCIqJg4tsSkFBAA-jlgeQXwyOhYuBClygAmlIVNJa1UwmLgZW5wHoPS8qGj4ww4RAjyGIzo0-6JRKLiktJyCGoY-gNeTABmELJ6xycQZDDy-Zcqh4kMSW1weQYnAJB3D3JdK9ksIUikMuAIFNCGgEAB3CC1eo9YotDCyIFAA&debug=false&forceAllTransforms=true&modules=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&timeTravel=false&sourceType=unambiguous&lineWrap=false&presets=env&prettier=false&targets=&version=7.20.15&externalPlugins=&assumptions=%7B%7D)

**Expected behavior**:
no errors in runtime; no redundant super calls

### Environment

- babel version: 7.20.15 or 7.21.9

### Possible solution

_No response_

### Additional context

_No response_


Hints:
Hey @simakvladimir! 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.

Patch:
diff --git a/packages/babel-helper-create-class-features-plugin/src/decorators.ts b/packages/babel-helper-create-class-features-plugin/src/decorators.ts
--- a/packages/babel-helper-create-class-features-plugin/src/decorators.ts
+++ b/packages/babel-helper-create-class-features-plugin/src/decorators.ts
@@ -213,7 +213,11 @@ export function buildDecoratedClass(
   }
 
   return {
-    instanceNodes: [template.statement.ast`${t.cloneNode(initializeId)}(this)`],
+    instanceNodes: [
+      template.statement.ast`
+        ${t.cloneNode(initializeId)}(this)
+      ` as t.ExpressionStatement,
+    ],
     wrapClass(path: NodePath<t.Class>) {
       path.replaceWith(replacement);
       return path.get(classPathDesc) as NodePath;
diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts
--- a/packages/babel-helper-create-class-features-plugin/src/fields.ts
+++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts
@@ -585,7 +585,7 @@ function buildPrivateFieldInitLoose(
         writable: true,
         value: ${value}
       });
-    `,
+    ` as t.ExpressionStatement,
     prop,
   );
 }
@@ -607,7 +607,7 @@ function buildPrivateInstanceFieldInitSpec(
           // enumerable is always false for private elements
           writable: true,
           value: ${value},
-        })`,
+        })` as t.ExpressionStatement,
         prop,
       );
     }
@@ -622,7 +622,7 @@ function buildPrivateInstanceFieldInitSpec(
         writable: true,
         value: ${value}
       },
-    )`,
+    )` as t.ExpressionStatement,
     prop,
   );
 }
@@ -689,7 +689,7 @@ function buildPrivateMethodInitLoose(
           // writable is false by default
           value: ${methodId.name}
         });
-      `,
+      ` as t.ExpressionStatement,
       prop,
     );
   }
@@ -709,7 +709,7 @@ function buildPrivateMethodInitLoose(
           get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
           set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
         });
-      `,
+      ` as t.ExpressionStatement,
       prop,
     );
   }
@@ -766,7 +766,7 @@ function buildPrivateAccessorInitialization(
             get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
             set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
           });
-        `,
+        ` as t.ExpressionStatement,
         prop,
       );
     }
@@ -781,7 +781,7 @@ function buildPrivateAccessorInitialization(
         get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
         set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
       },
-    )`,
+    )` as t.ExpressionStatement,
     prop,
   );
 }
@@ -798,7 +798,7 @@ function buildPrivateInstanceMethodInitialization(
   if (!process.env.BABEL_8_BREAKING) {
     if (!state.availableHelper("classPrivateMethodInitSpec")) {
       return inheritPropComments(
-        template.statement.ast`${id}.add(${ref})`,
+        template.statement.ast`${id}.add(${ref})` as t.ExpressionStatement,
         prop,
       );
     }
@@ -809,7 +809,7 @@ function buildPrivateInstanceMethodInitialization(
     template.statement.ast`${helper}(
       ${t.thisExpression()},
       ${t.cloneNode(id)}
-    )`,
+    )` as t.ExpressionStatement,
     prop,
   );
 }
@@ -1095,7 +1095,8 @@ export function buildFieldsInitNodes(
   let classRefFlags = ClassRefFlag.None;
   let injectSuperRef: t.Identifier;
   const staticNodes: t.Statement[] = [];
-  const instanceNodes: t.Statement[] = [];
+  const instanceNodes: t.ExpressionStatement[] = [];
+  let lastInstanceNodeReturnsThis = false;
   // These nodes are pure and can be moved to the closest statement position
   const pureStaticNodes: t.FunctionDeclaration[] = [];
   let classBindingNode: t.ExpressionStatement | null = null;
@@ -1156,6 +1157,8 @@ export function buildFieldsInitNodes(
       }
     }
 
+    lastInstanceNodeReturnsThis = false;
+
     // TODO(ts): there are so many `ts-expect-error` inside cases since
     // ts can not infer type from pre-computed values (or a case test)
     // even change `isStaticBlock` to `t.isStaticBlock(prop)` will not make prop
@@ -1301,6 +1304,7 @@ export function buildFieldsInitNodes(
         instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop));
         break;
       case isInstance && isPublic && isField && !setPublicClassFields:
+        lastInstanceNodeReturnsThis = true;
         instanceNodes.push(
           // @ts-expect-error checked in switch
           buildPublicFieldInitSpec(t.thisExpression(), prop, file),
@@ -1324,6 +1328,7 @@ export function buildFieldsInitNodes(
   return {
     staticNodes: staticNodes.filter(Boolean),
     instanceNodes: instanceNodes.filter(Boolean),
+    lastInstanceNodeReturnsThis,
     pureStaticNodes: pureStaticNodes.filter(Boolean),
     classBindingNode,
     wrapClass(path: NodePath<t.Class>) {
diff --git a/packages/babel-helper-create-class-features-plugin/src/index.ts b/packages/babel-helper-create-class-features-plugin/src/index.ts
--- a/packages/babel-helper-create-class-features-plugin/src/index.ts
+++ b/packages/babel-helper-create-class-features-plugin/src/index.ts
@@ -238,7 +238,8 @@ export function createClassFeaturePlugin({
 
         let keysNodes: t.Statement[],
           staticNodes: t.Statement[],
-          instanceNodes: t.Statement[],
+          instanceNodes: t.ExpressionStatement[],
+          lastInstanceNodeReturnsThis: boolean,
           pureStaticNodes: t.FunctionDeclaration[],
           classBindingNode: t.Statement | null,
           wrapClass: (path: NodePath<t.Class>) => NodePath;
@@ -258,6 +259,7 @@ export function createClassFeaturePlugin({
               staticNodes,
               pureStaticNodes,
               instanceNodes,
+              lastInstanceNodeReturnsThis,
               classBindingNode,
               wrapClass,
             } = buildFieldsInitNodes(
@@ -278,6 +280,7 @@ export function createClassFeaturePlugin({
             staticNodes,
             pureStaticNodes,
             instanceNodes,
+            lastInstanceNodeReturnsThis,
             classBindingNode,
             wrapClass,
           } = buildFieldsInitNodes(
@@ -308,6 +311,7 @@ export function createClassFeaturePlugin({
                 prop.traverse(referenceVisitor, state);
               }
             },
+            lastInstanceNodeReturnsThis,
           );
         }
 
diff --git a/packages/babel-helper-create-class-features-plugin/src/misc.ts b/packages/babel-helper-create-class-features-plugin/src/misc.ts
--- a/packages/babel-helper-create-class-features-plugin/src/misc.ts
+++ b/packages/babel-helper-create-class-features-plugin/src/misc.ts
@@ -64,8 +64,9 @@ interface RenamerState {
 export function injectInitialization(
   path: NodePath<t.Class>,
   constructor: NodePath<t.ClassMethod> | undefined,
-  nodes: t.Statement[],
+  nodes: t.ExpressionStatement[],
   renamer?: (visitor: Visitor<RenamerState>, state: RenamerState) => void,
+  lastReturnsThis?: boolean,
 ) {
   if (!nodes.length) return;
 
@@ -99,10 +100,19 @@ export function injectInitialization(
     let isFirst = true;
     for (const bareSuper of bareSupers) {
       if (isFirst) {
-        bareSuper.insertAfter(nodes);
         isFirst = false;
       } else {
-        bareSuper.insertAfter(nodes.map(n => t.cloneNode(n)));
+        nodes = nodes.map(n => t.cloneNode(n));
+      }
+      if (!bareSuper.parentPath.isExpressionStatement()) {
+        const allNodes: t.Expression[] = [
+          bareSuper.node,
+          ...nodes.map(n => t.toExpression(n)),
+        ];
+        if (!lastReturnsThis) allNodes.push(t.thisExpression());
+        bareSuper.replaceWith(t.sequenceExpression(allNodes));
+      } else {
+        bareSuper.insertAfter(nodes);
       }
     }
   } else {
diff --git a/packages/babel-plugin-transform-typescript/src/index.ts b/packages/babel-plugin-transform-typescript/src/index.ts
--- a/packages/babel-plugin-transform-typescript/src/index.ts
+++ b/packages/babel-plugin-transform-typescript/src/index.ts
@@ -205,7 +205,7 @@ export default declare((api, opts: Options) => {
       // property is only added once. This is necessary for cases like
       // using `transform-classes`, which causes this visitor to run
       // twice.
-      const assigns = [];
+      const assigns: t.ExpressionStatement[] = [];
       const { scope } = path;
       for (const paramPath of path.get("params")) {
         const param = paramPath.node;
@@ -226,8 +226,11 @@ export default declare((api, opts: Options) => {
               "Parameter properties can not be destructuring patterns.",
             );
           }
-          assigns.push(template.statement.ast`
-          this.${t.cloneNode(id)} = ${t.cloneNode(id)}`);
+          assigns.push(
+            template.statement.ast`
+              this.${t.cloneNode(id)} = ${t.cloneNode(id)}
+            ` as t.ExpressionStatement,
+          );
 
           paramPath.replaceWith(paramPath.get("parameter"));
           scope.registerBinding("param", paramPath);


Test patch:
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-complex/output.js b/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-complex/output.js
--- a/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-complex/output.js
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-complex/output.js
@@ -1,3 +1,3 @@
 class Foo extends Bar {
-  constructor(x = test ? (() => (super(), babelHelpers.defineProperty(this, "bar", "foo"), this))() : 0) {}
+  constructor(x = test ? (super(), babelHelpers.defineProperty(this, "bar", "foo")) : 0) {}
 }
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-in-arrow/output.js b/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-in-arrow/output.js
--- a/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-in-arrow/output.js
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params-in-arrow/output.js
@@ -1,5 +1,5 @@
 class Foo extends Bar {
   constructor(x = () => {
-    check((super(), babelHelpers.defineProperty(this, "bar", "foo"), this));
+    check((super(), babelHelpers.defineProperty(this, "bar", "foo")));
   }) {}
 }
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params/output.js b/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params/output.js
--- a/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params/output.js
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/public/derived-super-in-default-params/output.js
@@ -1,3 +1,3 @@
 class Foo extends Bar {
-  constructor(x = (() => (super(), babelHelpers.defineProperty(this, "bar", "foo"), this))()) {}
+  constructor(x = (super(), babelHelpers.defineProperty(this, "bar", "foo"))) {}
 }
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/public/super-expression/output.js b/packages/babel-plugin-transform-class-properties/test/fixtures/public/super-expression/output.js
--- a/packages/babel-plugin-transform-class-properties/test/fixtures/public/super-expression/output.js
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/public/super-expression/output.js
@@ -6,7 +6,7 @@ var Foo = /*#__PURE__*/function (_Bar) {
   function Foo() {
     var _this;
     babelHelpers.classCallCheck(this, Foo);
-    foo((_this = _super.call(this), babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "bar", "foo"), babelHelpers.assertThisInitialized(_this)));
+    foo((_this = _super.call(this), babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "bar", "foo")));
     return _this;
   }
   return babelHelpers.createClass(Foo);
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/regression/7371/output.js b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/7371/output.js
--- a/packages/babel-plugin-transform-class-properties/test/fixtures/regression/7371/output.js
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/7371/output.js
@@ -45,7 +45,7 @@ class ComputedMethod extends Obj {
         super();
         expect(this.field).toBeUndefined();
       }
-      [(super(), babelHelpers.defineProperty(this, "field", 1), this)]() {}
+      [(super(), babelHelpers.defineProperty(this, "field", 1))]() {}
     }
     expect(this.field).toBe(1);
     new B();
@@ -57,7 +57,7 @@ new ComputedMethod();
 class ComputedField extends Obj {
   constructor() {
     let _ref;
-    _ref = (super(), babelHelpers.defineProperty(this, "field", 1), this);
+    _ref = (super(), babelHelpers.defineProperty(this, "field", 1));
     class B extends Obj {
       constructor() {
         super();
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/input.js b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/input.js
@@ -0,0 +1,6 @@
+class A extends B {
+  x = 2;
+  constructor() {
+    x ? super(a) : super(b)
+  }
+}
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/options.json b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/options.json
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/options.json
@@ -0,0 +1,3 @@
+{
+  "plugins": ["transform-class-properties"]
+}
diff --git a/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/output.js b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/output.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-class-properties/test/fixtures/regression/multiple-super-in-termary/output.js
@@ -0,0 +1,5 @@
+class A extends B {
+  constructor() {
+    x ? (super(a), babelHelpers.defineProperty(this, "x", 2)) : (super(b), babelHelpers.defineProperty(this, "x", 2));
+  }
+}