Repository: swc-project/swc (rust)

Issue:
Ability to disable TS enum value inlining?
### Describe the feature

Given the following code:

```ts
enum D {
  A,
  B,
}

(D as any).A = 5;
console.log(D.A);
```

swc 1.3.88 outputs 5 and 1.3.89 outputs 0. This is because swc started inlining enums within a module.

```js
var D;
(function(D) {
    D[D["A"] = 0] = "A";
    D[D["B"] = 1] = "B";
})(D || (D = {}));
D.A = 5;
console.log(0);
```

Is there a way to disable this optimization? Although unlikely, I'm concerned it might cause bugs in people's Deno code since it would be a breaking change.

### Babel plugin or link to the feature description

_No response_

### Additional context

_No response_

Pull request description:
feat(es/typescript): Add `ts_enum_is_mutable` to disable enum inlining
**Description:**

This adds the ability to disable the enum inlining optimization that was recently introduced as the default.

This only updates the Rust API and nothing else.

**Related issue:**

 - Closes #8114.


Patch:
diff --git a/crates/swc_ecma_transforms_typescript/src/config.rs b/crates/swc_ecma_transforms_typescript/src/config.rs
index 6939b0efc3..e93d9a99b8 100644
--- a/crates/swc_ecma_transforms_typescript/src/config.rs
+++ b/crates/swc_ecma_transforms_typescript/src/config.rs
@@ -18,6 +18,14 @@ pub struct Config {
 
     #[serde(default)]
     pub import_export_assign_config: TsImportExportAssignConfig,
+
+    /// Disables an optimization that inlines TS enum member values
+    /// within the same module that assumes the enum member values
+    /// are never modified.
+    ///
+    /// Defaults to false.
+    #[serde(default)]
+    pub ts_enum_is_mutable: bool,
 }
 
 #[derive(Debug, Default, Serialize, Deserialize)]
diff --git a/crates/swc_ecma_transforms_typescript/src/transform.rs b/crates/swc_ecma_transforms_typescript/src/transform.rs
index 37b8455c41..568999a535 100644
--- a/crates/swc_ecma_transforms_typescript/src/transform.rs
+++ b/crates/swc_ecma_transforms_typescript/src/transform.rs
@@ -51,6 +51,7 @@ pub(crate) struct Transform {
     top_level_ctxt: SyntaxContext,
 
     import_export_assign_config: TsImportExportAssignConfig,
+    ts_enum_is_mutable: bool,
     verbatim_module_syntax: bool,
 
     namespace_id: Option<Id>,
@@ -64,12 +65,14 @@ pub(crate) struct Transform {
 pub fn transform(
     top_level_mark: Mark,
     import_export_assign_config: TsImportExportAssignConfig,
+    ts_enum_is_mutable: bool,
     verbatim_module_syntax: bool,
 ) -> impl Fold + VisitMut {
     as_folder(Transform {
         top_level_mark,
         top_level_ctxt: SyntaxContext::empty().apply_mark(top_level_mark),
         import_export_assign_config,
+        ts_enum_is_mutable,
         verbatim_module_syntax,
         ..Default::default()
     })
@@ -81,13 +84,10 @@ impl VisitMut for Transform {
     fn visit_mut_program(&mut self, n: &mut Program) {
         n.visit_mut_children_with(self);
 
-        if self.record.is_empty() {
-            return;
+        if !self.ts_enum_is_mutable && !self.record.is_empty() {
+            let record = mem::take(&mut self.record);
+            n.visit_mut_children_with(&mut InlineEnum::new(record));
         }
-
-        let record = mem::take(&mut self.record);
-
-        n.visit_mut_children_with(&mut InlineEnum::new(record));
     }
 
     fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
diff --git a/crates/swc_ecma_transforms_typescript/src/typescript.rs b/crates/swc_ecma_transforms_typescript/src/typescript.rs
index 0e3296d273..dc6fc07cd4 100644
--- a/crates/swc_ecma_transforms_typescript/src/typescript.rs
+++ b/crates/swc_ecma_transforms_typescript/src/typescript.rs
@@ -46,6 +46,7 @@ impl VisitMut for TypeScript {
         n.visit_mut_with(&mut transform(
             self.top_level_mark,
             self.config.import_export_assign_config,
+            self.config.ts_enum_is_mutable,
             self.config.verbatim_module_syntax,
         ));
 


Test patch:
diff --git a/crates/swc_ecma_transforms_typescript/tests/strip.rs b/crates/swc_ecma_transforms_typescript/tests/strip.rs
index 6c8b564bd2..43ab4caa60 100644
--- a/crates/swc_ecma_transforms_typescript/tests/strip.rs
+++ b/crates/swc_ecma_transforms_typescript/tests/strip.rs
@@ -4552,3 +4552,34 @@ test!(
     }
       "
 );
+
+test!(
+    Syntax::Typescript(TsConfig::default()),
+    |_| tr_config(
+        Some(typescript::Config {
+            ts_enum_is_mutable: true,
+            ..Default::default()
+        }),
+        None,
+        true,
+    ),
+    ts_enum_is_mutable_true,
+    r#"
+    enum D {
+      A,
+      B,
+    }
+
+    (D as any).A = 5;
+    console.log(D.A);
+    "#,
+    r#"
+    var D;
+    (function(D) {
+        D[D["A"] = 0] = "A";
+        D[D["B"] = 1] = "B";
+    })(D || (D = {}));
+    D.A = 5;
+    console.log(D.A);
+    "#
+);