Repository: swc-project/swc (rust)

Issue:
swc_emca_codegen omits "readonly" when printing `TsIndexSignature`
### Describe the bug

I'm writing a compiler for a new programming language that complies to .js + .d.ts.  I'm using `swc_ecma_codegen` and noticed that it doesn't output a `readonly` modifier even when the `.readonly` field is set to `true` on the `TsIndexSignature` struct.

The fix for this is pretty simple.

**BEFORE**
```
    fn emit_ts_index_signature(&mut self, n: &TsIndexSignature) -> Result {
        self.emit_leading_comments_of_span(n.span(), false)?;

        punct!("[");
        self.emit_list(n.span, Some(&n.params), ListFormat::Parameters)?;
        punct!("]");

        if let Some(type_ann) = &n.type_ann {
            punct!(":");
            formatting_space!();
            emit!(type_ann);
        }
    }
```

**AFTER**
```
    fn emit_ts_index_signature(&mut self, n: &TsIndexSignature) -> Result {
        self.emit_leading_comments_of_span(n.span(), false)?;

        if n.readonly {
            keyword!("readonly");
        }

        punct!("[");
        self.emit_list(n.span, Some(&n.params), ListFormat::Parameters)?;
        punct!("]");

        if let Some(type_ann) = &n.type_ann {
            punct!(":");
            formatting_space!();
            emit!(type_ann);
        }
    }
```

### Input code

_No response_

### Config

_No response_

### Playground link

n/a (the playground doesn't output .d.ts)

### Expected behavior

`swc_ecma_codegen` should include the `readonly` modifier if `.readonly` is set to `true` on the `TsIndexSignature` struct.

### Actual behavior

The `readonly` modifier is omitted even if the `.readonly` field is set to `true`.

### Version

main

### Additional context

I can create a PR to fix this issue.

Pull request description:
fix(es/codegen): Ensure 'readonly' modified included when emitting TsIndexSignature
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

This change updates `swc_ecma_codegen` so that it emits a `readonly` modified on index signatures when appropriate.

**BREAKING CHANGE:**

This is a minor bug fix and people shouldn't have been relying on the current behaviour.

**Related issue (if exists):**

Closes #6171

Patch:
diff --git a/crates/swc_ecma_codegen/src/typescript.rs b/crates/swc_ecma_codegen/src/typescript.rs
index 2e4c7c2434..df5955244e 100644
--- a/crates/swc_ecma_codegen/src/typescript.rs
+++ b/crates/swc_ecma_codegen/src/typescript.rs
@@ -297,6 +297,11 @@ where
     fn emit_ts_index_signature(&mut self, n: &TsIndexSignature) -> Result {
         self.emit_leading_comments_of_span(n.span(), false)?;
 
+        if n.readonly {
+            keyword!("readonly");
+            formatting_space!();
+        }
+
         punct!("[");
         self.emit_list(n.span, Some(&n.params), ListFormat::Parameters)?;
         punct!("]");


Test patch:
diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/6171/input.ts b/crates/swc_ecma_codegen/tests/fixture/issues/6171/input.ts
new file mode 100644
index 0000000000..00a3cc43a3
--- /dev/null
+++ b/crates/swc_ecma_codegen/tests/fixture/issues/6171/input.ts
@@ -0,0 +1,6 @@
+type ReadonlyDict = {
+    readonly [key: string]: string;
+};
+type Dict = {
+    [key: string]: string;
+};
diff --git a/crates/swc_ecma_codegen/tests/fixture/issues/6171/output.ts b/crates/swc_ecma_codegen/tests/fixture/issues/6171/output.ts
new file mode 100644
index 0000000000..00a3cc43a3
--- /dev/null
+++ b/crates/swc_ecma_codegen/tests/fixture/issues/6171/output.ts
@@ -0,0 +1,6 @@
+type ReadonlyDict = {
+    readonly [key: string]: string;
+};
+type Dict = {
+    [key: string]: string;
+};