Repository: alloy-framework/alloy
Pull request #225 (2025-06-26 22:29:55)

Parameter correct formatting when using multi lines

pkg-pr-new[bot]: 
[Open in StackBlitz](https://pkg.pr.new/template/b061155c-21e1-44a5-8989-b7952da17db8)


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

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

</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@225
```

</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@225
```

</p></details>
      
    

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

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

</p></details>
      
    

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

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

</p></details>
      
    

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

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

</p></details>
      
    

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

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

</p></details>
      
    

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

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

</p></details>
      
    

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

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

</p></details>
      
    

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

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

</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@225
```

</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@225
```

</p></details>
      
    

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

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

</p></details>
      
    

_commit: <a href="https://github.com/alloy-framework/alloy/runs/44887294206"><code>fdf1812</code></a>_


Patch:
diff --git a/.chronus/changes/parameters-formatting-2025-5-26-22-30-22.md b/.chronus/changes/parameters-formatting-2025-5-26-22-30-22.md
new file mode 100644
index 0000000..6935bf2
--- /dev/null
+++ b/.chronus/changes/parameters-formatting-2025-5-26-22-30-22.md
@@ -0,0 +1,8 @@
+---
+# Change versionKind to one of: breaking, feature, fix, internal
+changeKind: feature
+packages:
+  - "@alloy-js/csharp"
+---
+
+Parameter improved formatting when using multi lines
diff --git a/packages/csharp/src/components/ClassDeclaration.tsx b/packages/csharp/src/components/ClassDeclaration.tsx
index 9e0bae6..75eed6c 100644
--- a/packages/csharp/src/components/ClassDeclaration.tsx
+++ b/packages/csharp/src/components/ClassDeclaration.tsx
@@ -9,9 +9,9 @@ import {
 import { CSharpElements, useCSharpNamePolicy } from "../name-policy.js";
 import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
 import { CSharpMemberScope, useCSharpScope } from "../symbols/scopes.js";
-import { Name } from "./Name.jsx";
-import { ParameterProps, Parameters } from "./Parameters.jsx";
 import { DocWhen } from "./doc/comment.jsx";
+import { Name } from "./Name.jsx";
+import { ParameterProps, Parameters } from "./parameters/parameters.jsx";
 import { TypeParameterConstraints } from "./type-parameters/type-parameter-constraints.jsx";
 import { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
 import { TypeParameters } from "./type-parameters/type-parameters.jsx";
@@ -161,15 +161,14 @@ export function ClassConstructor(props: ClassConstructorProps) {
 
   const modifiers = computeModifiersPrefix([getAccessModifier(props)]);
 
-  const params =
-    props.parameters ? <Parameters parameters={props.parameters} /> : "";
-
   // note that scope wraps the ctor decl so that the params get the correct scope
   return (
     <core.Declaration symbol={ctorSymbol}>
       <core.Scope value={ctorDeclScope}>
         {modifiers}
-        <Name />({params})<core.Block newline>{props.children}</core.Block>
+        <Name />
+        <Parameters parameters={props.parameters} />
+        <core.Block newline>{props.children}</core.Block>
       </core.Scope>
     </core.Declaration>
   );
diff --git a/packages/csharp/src/components/ClassMethod.tsx b/packages/csharp/src/components/ClassMethod.tsx
index 04f9667..4534a45 100644
--- a/packages/csharp/src/components/ClassMethod.tsx
+++ b/packages/csharp/src/components/ClassMethod.tsx
@@ -16,8 +16,8 @@ import {
 import { useCSharpNamePolicy } from "../name-policy.js";
 import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
 import { CSharpMemberScope, useCSharpScope } from "../symbols/scopes.js";
-import { ParameterProps, Parameters } from "./Parameters.jsx";
 import { DocWhen } from "./doc/comment.jsx";
+import { ParameterProps, Parameters } from "./parameters/parameters.jsx";
 import { TypeParameterConstraints } from "./type-parameters/type-parameter-constraints.jsx";
 import { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
 import { TypeParameters } from "./type-parameters/type-parameters.jsx";
@@ -88,8 +88,6 @@ export function ClassMethod(props: ClassMethodProps) {
     owner: methodSymbol,
   });
 
-  const params =
-    props.parameters ? <Parameters parameters={props.parameters} /> : "";
   const returns = props.returns ?? (props.async ? "Task" : "void");
 
   const modifiers = computeModifiersPrefix([
@@ -107,7 +105,7 @@ export function ClassMethod(props: ClassMethodProps) {
         {props.typeParameters && (
           <TypeParameters parameters={props.typeParameters} />
         )}
-        ({params})
+        <Parameters parameters={props.parameters} />
         {props.typeParameters && (
           <TypeParameterConstraints parameters={props.typeParameters} />
         )}
diff --git a/packages/csharp/src/components/index.ts b/packages/csharp/src/components/index.ts
index 1123992..3e7bb6d 100644
--- a/packages/csharp/src/components/index.ts
+++ b/packages/csharp/src/components/index.ts
@@ -9,7 +9,7 @@ export * from "./interface/method.js";
 export * from "./interface/property.js";
 export * from "./Name.js";
 export * from "./Namespace.js";
-export * from "./Parameters.js";
+export * from "./parameters/parameters.jsx";
 export * from "./ProjectDirectory.js";
 export * from "./property/property.jsx";
 export * from "./record/declaration.js";
diff --git a/packages/csharp/src/components/interface/method.tsx b/packages/csharp/src/components/interface/method.tsx
index 7cc9ca3..3b6feea 100644
--- a/packages/csharp/src/components/interface/method.tsx
+++ b/packages/csharp/src/components/interface/method.tsx
@@ -15,8 +15,8 @@ import {
 import { useCSharpNamePolicy } from "../../name-policy.js";
 import { CSharpOutputSymbol } from "../../symbols/csharp-output-symbol.js";
 import { CSharpMemberScope, useCSharpScope } from "../../symbols/scopes.js";
-import { ParameterProps, Parameters } from "../Parameters.jsx";
 import { DocWhen } from "../doc/comment.jsx";
+import { ParameterProps, Parameters } from "../parameters/parameters.jsx";
 import { TypeParameterConstraints } from "../type-parameters/type-parameter-constraints.jsx";
 import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
 import { TypeParameters } from "../type-parameters/type-parameters.jsx";
@@ -75,9 +75,6 @@ export function InterfaceMethod(props: InterfaceMethodProps) {
     owner: methodSymbol,
   });
 
-  const params =
-    props.parameters ? <Parameters parameters={props.parameters} /> : "";
-
   const modifiers = computeModifiersPrefix([
     getAccessModifier(props),
     getMethodModifier(props),
@@ -92,7 +89,7 @@ export function InterfaceMethod(props: InterfaceMethodProps) {
         {props.typeParameters && (
           <TypeParameters parameters={props.typeParameters} />
         )}
-        ({params})
+        <Parameters parameters={props.parameters} />
         {props.typeParameters && (
           <TypeParameterConstraints parameters={props.typeParameters} />
         )}
diff --git a/packages/csharp/src/components/Parameters.tsx b/packages/csharp/src/components/parameters/parameters.tsx
similarity index 51%
rename from packages/csharp/src/components/Parameters.tsx
rename to packages/csharp/src/components/parameters/parameters.tsx
index 4a903a9..da42a96 100644
--- a/packages/csharp/src/components/Parameters.tsx
+++ b/packages/csharp/src/components/parameters/parameters.tsx
@@ -1,19 +1,27 @@
-import * as core from "@alloy-js/core";
-import { code } from "@alloy-js/core";
-import { useCSharpNamePolicy } from "../name-policy.js";
-import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
-import { useCSharpScope } from "../symbols/scopes.js";
-import { Name } from "./Name.js";
+import {
+  Children,
+  code,
+  Declaration,
+  For,
+  Indent,
+  OutputSymbol,
+  refkey,
+  Refkey,
+} from "@alloy-js/core";
+import { useCSharpNamePolicy } from "../../name-policy.js";
+import { CSharpOutputSymbol } from "../../symbols/csharp-output-symbol.js";
+import { useCSharpScope } from "../../symbols/scopes.js";
+import { Name } from "../Name.jsx";
 
 export interface ParameterProps {
   name: string;
-  type: core.Children;
+  type: Children;
   /** If the parmaeter is optional(without default value) */
   optional?: boolean;
   /** Default value for the parameter */
-  default?: core.Children;
-  refkey?: core.Refkey;
-  symbol?: core.OutputSymbol;
+  default?: Children;
+  refkey?: Refkey;
+  symbol?: OutputSymbol;
 }
 
 /** Define a parameter to be used in class or interface method. */
@@ -31,28 +39,36 @@ export function Parameter(props: ParameterProps) {
 
   const memberSymbol = new CSharpOutputSymbol(name, {
     scope,
-    refkeys: props.refkey ?? core.refkey(props.name),
+    refkeys: props.refkey ?? refkey(props.name),
   });
 
   return (
-    <core.Declaration symbol={memberSymbol}>
+    <Declaration symbol={memberSymbol}>
       {props.type}
       {props.optional ? "?" : ""} <Name />
       {props.default ? code` = ${props.default}` : ""}
-    </core.Declaration>
+    </Declaration>
   );
 }
 
 export interface ParametersProps {
-  // param name and type
-  parameters: ParameterProps[];
+  parameters: ParameterProps[] | undefined;
 }
 
-// a collection of parameters
+/** Render a collection of parameters */
 export function Parameters(props: ParametersProps) {
   return (
-    <core.For each={props.parameters} joiner={", "}>
-      {(param) => <Parameter {...param} />}
-    </core.For>
+    <group>
+      {"("}
+      {props.parameters && (
+        <Indent softline>
+          <For each={props.parameters} joiner={", "}>
+            {(param) => <Parameter {...param} />}
+          </For>
+        </Indent>
+      )}
+      <softline />
+      {")"}
+    </group>
   );
 }


Test patch:
diff --git a/packages/csharp/src/components/interface/method.test.tsx b/packages/csharp/src/components/interface/method.test.tsx
index 08b67df..567102d 100644
--- a/packages/csharp/src/components/interface/method.test.tsx
+++ b/packages/csharp/src/components/interface/method.test.tsx
@@ -248,3 +248,31 @@ describe("with type parameters", () => {
     `);
   });
 });
+
+describe("formatting", () => {
+  it("Split parameters before type parameters", () => {
+    expect(
+      <Wrapper>
+        <InterfaceMethod
+          public
+          name="Handle"
+          parameters={[
+            {
+              name: "message",
+              type: "Some.Quite.Long.Type.That.Will.Split",
+            },
+          ]}
+          typeParameters={["T"]}
+          returns="Some.Quite.Long.Type.That.Will.Split"
+        />
+      </Wrapper>,
+    ).toRenderTo(`
+      public interface TestInterface
+      {
+        public Some.Quite.Long.Type.That.Will.Split Handle<T>(
+          Some.Quite.Long.Type.That.Will.Split message
+        );
+      }
+    `);
+  });
+});