Repository: babel/babel (TypeScript)

Issue:
[Bug]: babel compile `proposal-explicit-resource-management` different from `tsc`
### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

@babel/cli

### Input code

https://github.com/microsoft/TypeScript/issues/58234

```js
import { deepStrictEqual } from 'node:assert'
import process from 'node:process'

let i = 0
/** @type {any} */
let err
try {
  await using _x1 = {
    async [Symbol.asyncDispose]() {
      throw [1, ++i]
    }
  }

  await using _x2 = {
    async [Symbol.asyncDispose]() {
      throw [2, ++i]
    }
  }

  await using _x3 = {
    async [Symbol.asyncDispose]() {
      throw [3, ++i]
    }
  }

  await using _x4 = {
    async [Symbol.asyncDispose]() {
      throw [4, ++i]
    }
  }

  throw [5, ++i]
} catch (e) {
  err = e
}

switch (process.env['TRANSPILER']) {
  case 'tsc':
    deepStrictEqual(err.error, [1, 5])
    deepStrictEqual(err.suppressed.error, [2, 4])
    deepStrictEqual(err.suppressed.suppressed.error, [3, 3])
    deepStrictEqual(err.suppressed.suppressed.suppressed.error, [4, 2])
    deepStrictEqual(err.suppressed.suppressed.suppressed.suppressed, [5, 1])
    break
  case 'swc':
    deepStrictEqual(err.suppressed, [1, 5])
    deepStrictEqual(err.error.suppressed, [2, 4])
    deepStrictEqual(err.error.error.suppressed, [3, 3])
    deepStrictEqual(err.error.error.error.suppressed, [4, 2])
    deepStrictEqual(err.error.error.error.error, [5, 1])
    break
  case 'babel':
    deepStrictEqual(err.suppressed, [1, 5])
    deepStrictEqual(err.error.suppressed, [2, 4])
    deepStrictEqual(err.error.error.suppressed, [3, 3])
    deepStrictEqual(err.error.error.error.suppressed, [4, 2])
    deepStrictEqual(err.error.error.error.error, [5, 1])
    break
  default:
    // break
    throw new Error()
}

// export { err }
```


### Configuration file name

_No response_

### Configuration

_No response_

### Current and expected behavior

Currently, `tsc` and `swc` and `babel` does not have same runtime behavior.

Expect `tsc` and `swc` and `babel` have same runtime behavior.


### Environment

7.24.1 (@babel/core 7.24.4)

### Possible solution

_No response_

### Additional context

_No response_


Hints:
Hey @loynoir! 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.
If anybody wants to fix this, the problem is in the order we pass errors to the `SuppressedError` constructor in https://github.com/babel/babel/blob/33d8d7d54e1d2eb2d55c455a3ff34a73b55bd569/packages/babel-helpers/src/helpers/usingCtx.ts. After fixing that, we probably need to update some tests that are asserting the wrong thing.

This would be a good first contribution for anybody interested :)

<!-- ALERT!!!!!!!
    Before submitting this comment, please:
      1. Write where to start searching the bug
      2. Write where to add a new test
    See https://github.com/babel/babel/issues/9563#issuecomment-466799807 for an example
-->

If it is the first time that you contribute to Babel, follow these steps: (you need to have `make` and `yarn` available on your machine)
1. **Write a comment there** to let other possible contributors know that you are working on this bug.
1. Fork the repo
1. Run `git clone https://github.com/<YOUR_USERNAME>/babel.git && cd babel`
1. Run `yarn && make bootstrap`
1. Wait :hourglass_flowing_sand: 
1. Run `make watch` (or `make build` whenever you change a file)
   - NOTE: When changing helpers code, `make watch` is not always reliable so you should run `make build`
1. Add a test (only `input.js`; `output.js` will be automatically generated)
1. Update the code!
1. `yarn jest explicit-resource-management` to run the tests
    - You will probably need to update some assertions in failing tests
    - If some snapshot test outputs don't match but the new results are correct, you can delete the bad `output.js` files and run the tests again
      - If you prefer, you can run `OVERWRITE=true yarn jest explicit-resource-management` and they will be automatically updated.
1. If it is working, run `make test` to run all the tests
1. Run `git push` and open a PR!
hello! @nicolo-ribaudo  I am sossost, a new contributor. I would like to solve this problem. Is it possible?
Yes! Feel free to ask here if you need any help :)
thank you! If there is anything I need help with along the way, I will ask. have a good day

Patch:
diff --git a/packages/babel-helpers/src/helpers-generated.ts b/packages/babel-helpers/src/helpers-generated.ts
--- a/packages/babel-helpers/src/helpers-generated.ts
+++ b/packages/babel-helpers/src/helpers-generated.ts
@@ -191,7 +191,7 @@ export default Object.freeze({
   // size: 922, gzip size: 481
   usingCtx: helper(
     "7.23.9",
-    'export default function _usingCtx(){var r="function"==typeof SuppressedError?SuppressedError:function(r,n){var e=Error();return e.name="SuppressedError",e.suppressed=n,e.error=r,e},n={},e=[];function using(r,n){if(null!=n){if(Object(n)!==n)throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");if(r)var o=n[Symbol.asyncDispose||Symbol.for("Symbol.asyncDispose")];if(null==o&&(o=n[Symbol.dispose||Symbol.for("Symbol.dispose")]),"function"!=typeof o)throw new TypeError("Property [Symbol.dispose] is not a function.");e.push({v:n,d:o,a:r})}else r&&e.push({d:n,a:r});return n}return{e:n,u:using.bind(null,!1),a:using.bind(null,!0),d:function(){var o=this.e;function next(){for(;r=e.pop();)try{var r,t=r.d&&r.d.call(r.v);if(r.a)return Promise.resolve(t).then(next,err)}catch(r){return err(r)}if(o!==n)throw o}function err(e){return o=o!==n?new r(o,e):e,next()}return next()}}}',
+    'export default function _usingCtx(){var r="function"==typeof SuppressedError?SuppressedError:function(r,n){var e=Error();return e.name="SuppressedError",e.error=r,e.suppressed=n,e},n={},e=[];function using(r,n){if(null!=n){if(Object(n)!==n)throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");if(r)var o=n[Symbol.asyncDispose||Symbol.for("Symbol.asyncDispose")];if(null==o&&(o=n[Symbol.dispose||Symbol.for("Symbol.dispose")]),"function"!=typeof o)throw new TypeError("Property [Symbol.dispose] is not a function.");e.push({v:n,d:o,a:r})}else r&&e.push({d:n,a:r});return n}return{e:n,u:using.bind(null,!1),a:using.bind(null,!0),d:function(){var o=this.e;function next(){for(;r=e.pop();)try{var r,t=r.d&&r.d.call(r.v);if(r.a)return Promise.resolve(t).then(next,err)}catch(r){return err(r)}if(o!==n)throw o}function err(e){return o=o!==n?new r(e,o):e,next()}return next()}}}',
   ),
   // size: 1252, gzip size: 572
   wrapRegExp: helper(
diff --git a/packages/babel-helpers/src/helpers/usingCtx.ts b/packages/babel-helpers/src/helpers/usingCtx.ts
--- a/packages/babel-helpers/src/helpers/usingCtx.ts
+++ b/packages/babel-helpers/src/helpers/usingCtx.ts
@@ -14,8 +14,8 @@ export default function _usingCtx() {
         : (function (error: Error, suppressed: Error) {
             var err = new Error() as SuppressedError;
             err.name = "SuppressedError";
-            err.suppressed = suppressed;
             err.error = error;
+            err.suppressed = suppressed;
             return err;
           } as SuppressedErrorConstructor),
     empty = {},
@@ -73,7 +73,7 @@ export default function _usingCtx() {
       }
 
       function err(e: Error) {
-        error = error !== empty ? new _disposeSuppressedError(error, e) : e;
+        error = error !== empty ? new _disposeSuppressedError(e, error) : e;
 
         return next();
       }
diff --git a/packages/babel-runtime-corejs3/helpers/esm/usingCtx.js b/packages/babel-runtime-corejs3/helpers/esm/usingCtx.js
--- a/packages/babel-runtime-corejs3/helpers/esm/usingCtx.js
+++ b/packages/babel-runtime-corejs3/helpers/esm/usingCtx.js
@@ -8,7 +8,7 @@ import _Promise from "core-js-pure/features/promise/index.js";
 export default function _usingCtx() {
   var r = "function" == typeof _SuppressedError ? _SuppressedError : function (r, n) {
       var e = Error();
-      return e.name = "SuppressedError", e.suppressed = n, e.error = r, e;
+      return e.name = "SuppressedError", e.error = r, e.suppressed = n, e;
     },
     n = {},
     e = [];
@@ -45,7 +45,7 @@ export default function _usingCtx() {
         if (o !== n) throw o;
       }
       function err(e) {
-        return o = o !== n ? new r(o, e) : e, next();
+        return o = o !== n ? new r(e, o) : e, next();
       }
       return next();
     }


Test patch:
diff --git a/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/async-dispose-throws-synchronously.js b/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/async-dispose-throws-synchronously.js
--- a/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/async-dispose-throws-synchronously.js
+++ b/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/async-dispose-throws-synchronously.js
@@ -1,4 +1,4 @@
-return async function () {
+return (async function () {
   let disposed = false;
   let beforeEnd;
 
@@ -10,13 +10,13 @@ return async function () {
     await using x = {
       [Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")]() {
         throw err1;
-      }
+      },
     };
     throw err2;
   } catch (e) {
     thrown = e;
   }
 
-  expect(thrown.suppressed).toBe(err1);
-  expect(thrown.error).toBe(err2);
-}();
\ No newline at end of file
+  expect(thrown.suppressed).toBe(err2);
+  expect(thrown.error).toBe(err1);
+})();
diff --git a/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/completion-throw.js b/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/completion-throw.js
--- a/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/completion-throw.js
+++ b/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-async/completion-throw.js
@@ -16,8 +16,8 @@ return (async function () {
   } catch (e) {
     inCatch = disposed;
     expect(e.name).toBe("SuppressedError");
-    expect(e.suppressed).toBe(1);
-    expect(e.error).toBe(0);
+    expect(e.suppressed).toBe(0);
+    expect(e.error).toBe(1);
   }
 
   expect(beforeReturn).toBe(false);
diff --git a/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-sync/completion-throw.js b/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-sync/completion-throw.js
--- a/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-sync/completion-throw.js
+++ b/packages/babel-plugin-proposal-explicit-resource-management/test/fixtures/exec-sync/completion-throw.js
@@ -15,8 +15,8 @@ try {
 } catch (e) {
   inCatch = disposed;
   expect(e.name).toBe("SuppressedError");
-  expect(e.suppressed).toBe(1);
-  expect(e.error).toBe(0);
+  expect(e.suppressed).toBe(0);
+  expect(e.error).toBe(1);
 }
 
 expect(beforeReturn).toBe(false);