Repository: alloy-framework/alloy
Pull request #208 (2025-06-19 08:15:58)

[TypeScript] Fix FunctionParameters component adds an extra comma when no params and function name is long
When the function name is long (and/or deeply indented), the formatter inserts a line break inside the function parameters parens and an extra comma is added by `<ifBreak>,</ifBreak>`. However, when the function have no parameters at all, it produces an invalid code snippet as follows:

```ts
function thisFunctionNameIsTooLongSoTheFormatterWillInsertLineBreakAndIfBreakNodes(
  ,
) {}
```

This pull request fixes the component to return just `null` when no parameters provided, so the extra comma will never be inserted by the formatter.

github-actions[bot]: <!--chronus-github-change-commenter-->
:x: There is undocummented changes. Run `chronus add` to add a changeset or [click here](https://github.com/siketyan/alloy/new/fix/function-params-extra-comma?filename=.chronus/changes/fix-function-params-extra-comma-2025-5-19-23-36-10.md&value=---%0A%23%20Change%20versionKind%20to%20one%20of%3A%20breaking%2C%20feature%2C%20fix%2C%20internal%0AchangeKind%3A%20fix%0Apackages%3A%0A%20%20-%20%22%40alloy-js%2Ftypescript%22%0A---%0A%0A%5BTypeScript%5D%20Fix%20FunctionParameters%20component%20adds%20an%20extra%20comma%20when%20no%20params%20and%20function%20name%20is%20long).

**The following packages have changes but are not documented.**
 - :x:`@alloy-js/typescript`

<details>
<summary>Show changes</summary>


</details>

pkg-pr-new[bot]: 
[Open in StackBlitz](https://pkg.pr.new/template/97ee7b7e-f867-4982-8146-164257541be1)


<details><summary><b>@alloy-js/babel-plugin</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/babel-plugin@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/babel-plugin-jsx-dom-expressions</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/babel-plugin-jsx-dom-expressions@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/babel-preset</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/babel-preset@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/cli</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/cli@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/core</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/core@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/create</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/create@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/csharp</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/csharp@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/java</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/java@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/json</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/json@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/markdown</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/markdown@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/prettier-plugin-alloy</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/prettier-plugin-alloy@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/rollup-plugin</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/rollup-plugin@208
```

</p></details>
      
    

<details><summary><b>@alloy-js/typescript</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/typescript@208
```

</p></details>
      
    

_commit: <a href="https://github.com/alloy-framework/alloy/runs/44447823615"><code>75b353c</code></a>_


Patch:
diff --git a/.chronus/changes/fix-function-params-extra-comma-2025-5-20-16-4-40.md b/.chronus/changes/fix-function-params-extra-comma-2025-5-20-16-4-40.md
new file mode 100644
index 0000000..263b992
--- /dev/null
+++ b/.chronus/changes/fix-function-params-extra-comma-2025-5-20-16-4-40.md
@@ -0,0 +1,8 @@
+---
+# Change versionKind to one of: breaking, feature, fix, internal
+changeKind: fix
+packages:
+  - "@alloy-js/typescript"
+---
+
+Fix FunctionParameters component adds an extra comma when no params and function name is long
diff --git a/packages/typescript/src/components/FunctionBase.tsx b/packages/typescript/src/components/FunctionBase.tsx
index 7f3a3dd..f155843 100644
--- a/packages/typescript/src/components/FunctionBase.tsx
+++ b/packages/typescript/src/components/FunctionBase.tsx
@@ -73,6 +73,10 @@ export const FunctionParameters = taggedComponent(
     }
 
     const parameters = normalizeAndDeclareParameters(props.parameters ?? []);
+    if (parameters.length === 0) {
+      return null;
+    }
+
     return (
       <group>
         <Indent softline trailingBreak>
@@ -103,6 +107,10 @@ export const FunctionTypeParameters = taggedComponent(
     }
 
     const parameters = normalizeAndDeclareParameters(props.parameters ?? []);
+    if (parameters.length === 0) {
+      return null;
+    }
+
     return (
       <group>
         <Indent softline trailingBreak>


Test patch:
diff --git a/packages/typescript/test/function-declaration.test.tsx b/packages/typescript/test/function-declaration.test.tsx
index 9863981..36b3664 100644
--- a/packages/typescript/test/function-declaration.test.tsx
+++ b/packages/typescript/test/function-declaration.test.tsx
@@ -124,6 +124,18 @@ it("supports type parameters by element", () => {
   `);
 });
 
+it("do not add an extra comma when there is no parameters", () => {
+  expect(
+    toSourceText(
+      <FunctionDeclaration name="thisFunctionNameIsTooLongSoTheFormatterWillInsertLineBreakAndIfBreakNodes"></FunctionDeclaration>,
+    ),
+  ).toBe(d`
+    function thisFunctionNameIsTooLongSoTheFormatterWillInsertLineBreakAndIfBreakNodes() {
+
+    }
+  `);
+});
+
 describe("symbols", () => {
   it("creates a nested scope", () => {
     const innerRefkey = refkey();