@alloy-js/csharp 0.18.0-dev.2 → 0.18.0-dev.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/LICENSE +7 -0
  2. package/dist/src/components/ClassDeclaration.d.ts +74 -0
  3. package/dist/src/components/ClassDeclaration.d.ts.map +1 -0
  4. package/dist/src/components/{Class.js → ClassDeclaration.js} +59 -32
  5. package/dist/src/components/ClassMethod.d.ts +25 -4
  6. package/dist/src/components/ClassMethod.d.ts.map +1 -1
  7. package/dist/src/components/ClassMethod.js +22 -3
  8. package/dist/src/components/EnumDeclaration.d.ts +34 -0
  9. package/dist/src/components/EnumDeclaration.d.ts.map +1 -0
  10. package/dist/src/components/{Enum.js → EnumDeclaration.js} +25 -5
  11. package/dist/src/components/Parameters.d.ts +6 -1
  12. package/dist/src/components/Parameters.d.ts.map +1 -1
  13. package/dist/src/components/Parameters.js +3 -2
  14. package/dist/src/components/doc/comment.d.ts +70 -0
  15. package/dist/src/components/doc/comment.d.ts.map +1 -0
  16. package/dist/src/components/doc/comment.js +88 -0
  17. package/dist/src/components/doc/comment.test.d.ts +2 -0
  18. package/dist/src/components/doc/comment.test.d.ts.map +1 -0
  19. package/dist/src/components/doc/comment.test.js +348 -0
  20. package/dist/src/components/doc/from-markdown.d.ts +6 -0
  21. package/dist/src/components/doc/from-markdown.d.ts.map +1 -0
  22. package/dist/src/components/doc/from-markdown.js +58 -0
  23. package/dist/src/components/doc/from-markdown.test.d.ts +2 -0
  24. package/dist/src/components/doc/from-markdown.test.d.ts.map +1 -0
  25. package/dist/src/components/doc/from-markdown.test.js +83 -0
  26. package/dist/src/components/index.d.ts +12 -3
  27. package/dist/src/components/index.d.ts.map +1 -1
  28. package/dist/src/components/index.js +13 -4
  29. package/dist/src/components/interface/declaration.d.ts +47 -0
  30. package/dist/src/components/interface/declaration.d.ts.map +1 -0
  31. package/dist/src/components/interface/declaration.js +77 -0
  32. package/dist/src/components/interface/declaration.test.d.ts +2 -0
  33. package/dist/src/components/interface/declaration.test.d.ts.map +1 -0
  34. package/dist/src/components/interface/declaration.test.js +153 -0
  35. package/dist/src/components/interface/method.d.ts +32 -0
  36. package/dist/src/components/interface/method.d.ts.map +1 -0
  37. package/dist/src/components/interface/method.js +69 -0
  38. package/dist/src/components/interface/method.test.d.ts +2 -0
  39. package/dist/src/components/interface/method.test.d.ts.map +1 -0
  40. package/dist/src/components/interface/method.test.js +254 -0
  41. package/dist/src/components/interface/property.d.ts +38 -0
  42. package/dist/src/components/interface/property.d.ts.map +1 -0
  43. package/dist/src/components/interface/property.js +67 -0
  44. package/dist/src/components/interface/property.test.d.ts +2 -0
  45. package/dist/src/components/interface/property.test.d.ts.map +1 -0
  46. package/dist/src/components/interface/property.test.js +165 -0
  47. package/dist/src/components/property/property.d.ts +57 -0
  48. package/dist/src/components/property/property.d.ts.map +1 -0
  49. package/dist/src/components/property/property.js +70 -0
  50. package/dist/src/components/property/property.test.d.ts +2 -0
  51. package/dist/src/components/property/property.test.d.ts.map +1 -0
  52. package/dist/src/components/property/property.test.js +218 -0
  53. package/dist/src/components/record/declaration.d.ts +35 -0
  54. package/dist/src/components/record/declaration.d.ts.map +1 -0
  55. package/dist/src/components/record/declaration.js +90 -0
  56. package/dist/src/components/record/declaration.test.d.ts +2 -0
  57. package/dist/src/components/record/declaration.test.d.ts.map +1 -0
  58. package/dist/src/components/record/declaration.test.js +94 -0
  59. package/dist/src/components/stc/index.d.ts +2 -2
  60. package/dist/src/components/stc/index.d.ts.map +1 -1
  61. package/dist/src/components/stc/index.js +2 -2
  62. package/dist/src/components/type-parameters/type-parameter-constraints.d.ts +8 -0
  63. package/dist/src/components/type-parameters/type-parameter-constraints.d.ts.map +1 -0
  64. package/dist/src/components/type-parameters/type-parameter-constraints.js +44 -0
  65. package/dist/src/components/type-parameters/type-parameter-constraints.test.d.ts +2 -0
  66. package/dist/src/components/type-parameters/type-parameter-constraints.test.d.ts.map +1 -0
  67. package/dist/src/components/type-parameters/type-parameter-constraints.test.js +67 -0
  68. package/dist/src/components/type-parameters/type-parameter.d.ts +20 -0
  69. package/dist/src/components/type-parameters/type-parameter.d.ts.map +1 -0
  70. package/dist/src/components/type-parameters/type-parameter.js +22 -0
  71. package/dist/src/components/type-parameters/type-parameters.d.ts +17 -0
  72. package/dist/src/components/type-parameters/type-parameters.d.ts.map +1 -0
  73. package/dist/src/components/type-parameters/type-parameters.js +54 -0
  74. package/dist/src/components/type-parameters/type-parameters.test.d.ts +2 -0
  75. package/dist/src/components/type-parameters/type-parameters.test.d.ts.map +1 -0
  76. package/dist/src/components/type-parameters/type-parameters.test.js +48 -0
  77. package/dist/src/components/var/declaration.d.ts +35 -0
  78. package/dist/src/components/var/declaration.d.ts.map +1 -0
  79. package/dist/src/components/var/declaration.js +40 -0
  80. package/dist/src/components/var/declaration.test.d.ts +2 -0
  81. package/dist/src/components/var/declaration.test.d.ts.map +1 -0
  82. package/dist/src/components/var/declaration.test.js +73 -0
  83. package/dist/src/modifiers.d.ts +10 -4
  84. package/dist/src/modifiers.d.ts.map +1 -1
  85. package/dist/src/modifiers.js +9 -32
  86. package/dist/src/name-policy.d.ts +1 -1
  87. package/dist/src/name-policy.d.ts.map +1 -1
  88. package/dist/src/name-policy.js +2 -0
  89. package/dist/test/class-declaration.test.d.ts +2 -0
  90. package/dist/test/class-declaration.test.d.ts.map +1 -0
  91. package/dist/test/class-declaration.test.js +463 -0
  92. package/dist/test/class-method.test.js +37 -14
  93. package/dist/test/enum.test.js +12 -12
  94. package/dist/test/namespace.test.js +8 -8
  95. package/dist/test/project-directory.test.d.ts +2 -0
  96. package/dist/test/project-directory.test.d.ts.map +1 -0
  97. package/dist/test/{projectdirectory.test.js → project-directory.test.js} +8 -8
  98. package/dist/test/sourcefile.test.js +4 -4
  99. package/dist/test/using.test.js +9 -9
  100. package/dist/test/vitest.setup.d.ts +2 -0
  101. package/dist/test/vitest.setup.d.ts.map +1 -0
  102. package/dist/test/vitest.setup.js +1 -0
  103. package/dist/tsconfig.tsbuildinfo +1 -1
  104. package/package.json +21 -21
  105. package/src/components/{Class.tsx → ClassDeclaration.tsx} +108 -43
  106. package/src/components/ClassMethod.tsx +53 -12
  107. package/src/components/{Enum.tsx → EnumDeclaration.tsx} +30 -6
  108. package/src/components/Parameters.tsx +10 -3
  109. package/src/components/doc/comment.test.tsx +337 -0
  110. package/src/components/doc/comment.tsx +152 -0
  111. package/src/components/doc/from-markdown.test.tsx +103 -0
  112. package/src/components/doc/from-markdown.tsx +58 -0
  113. package/src/components/index.ts +12 -3
  114. package/src/components/interface/declaration.test.tsx +143 -0
  115. package/src/components/interface/declaration.tsx +105 -0
  116. package/src/components/interface/method.test.tsx +250 -0
  117. package/src/components/interface/method.tsx +105 -0
  118. package/src/components/interface/property.test.tsx +144 -0
  119. package/src/components/interface/property.tsx +107 -0
  120. package/src/components/property/property.test.tsx +187 -0
  121. package/src/components/property/property.tsx +146 -0
  122. package/src/components/record/declaration.test.tsx +73 -0
  123. package/src/components/record/declaration.tsx +109 -0
  124. package/src/components/stc/index.ts +2 -2
  125. package/src/components/type-parameters/type-parameter-constraints.test.tsx +93 -0
  126. package/src/components/type-parameters/type-parameter-constraints.tsx +46 -0
  127. package/src/components/type-parameters/type-parameter.tsx +35 -0
  128. package/src/components/type-parameters/type-parameters.test.tsx +46 -0
  129. package/src/components/type-parameters/type-parameters.tsx +63 -0
  130. package/src/components/var/declaration.test.tsx +59 -0
  131. package/src/components/var/declaration.tsx +47 -0
  132. package/src/modifiers.ts +25 -42
  133. package/src/name-policy.ts +5 -0
  134. package/temp/api.json +5227 -685
  135. package/test/class-declaration.test.tsx +418 -0
  136. package/test/class-method.test.tsx +24 -14
  137. package/test/enum.test.tsx +11 -11
  138. package/test/namespace.test.tsx +4 -4
  139. package/test/{projectdirectory.test.tsx → project-directory.test.tsx} +4 -4
  140. package/test/sourcefile.test.tsx +2 -2
  141. package/test/using.test.tsx +9 -9
  142. package/test/vitest.setup.ts +1 -0
  143. package/vitest.config.ts +3 -0
  144. package/dist/src/components/Class.d.ts +0 -26
  145. package/dist/src/components/Class.d.ts.map +0 -1
  146. package/dist/src/components/Enum.d.ts +0 -15
  147. package/dist/src/components/Enum.d.ts.map +0 -1
  148. package/dist/test/class.test.d.ts +0 -2
  149. package/dist/test/class.test.d.ts.map +0 -1
  150. package/dist/test/class.test.js +0 -298
  151. package/dist/test/projectdirectory.test.d.ts +0 -2
  152. package/dist/test/projectdirectory.test.d.ts.map +0 -1
  153. package/test/class.test.tsx +0 -292
@@ -0,0 +1,143 @@
1
+ import { List, refkey } from "@alloy-js/core";
2
+ import { describe, expect, it } from "vitest";
3
+ import { TestNamespace } from "../../../test/utils.jsx";
4
+ import { SourceFile } from "../SourceFile.jsx";
5
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
6
+ import { InterfaceDeclaration } from "./declaration.jsx";
7
+ import { InterfaceProperty } from "./property.jsx";
8
+
9
+ it("declares class with no members", () => {
10
+ expect(
11
+ <TestNamespace>
12
+ <InterfaceDeclaration name="TestInterface" />
13
+ </TestNamespace>,
14
+ ).toRenderTo(`
15
+ interface TestInterface;
16
+ `);
17
+ });
18
+
19
+ describe("modifiers", () => {
20
+ it.each(["public", "private", "internal"])("%s", (mod) => {
21
+ expect(
22
+ <TestNamespace>
23
+ <InterfaceDeclaration {...{ [mod]: true }} name="TestInterface" />
24
+ </TestNamespace>,
25
+ ).toRenderTo(`
26
+ ${mod} interface TestInterface;
27
+ `);
28
+ });
29
+
30
+ it.each(["partial"])("%s", (mod) => {
31
+ expect(
32
+ <TestNamespace>
33
+ <InterfaceDeclaration {...{ [mod]: true }} name="TestInterface" />
34
+ </TestNamespace>,
35
+ ).toRenderTo(`
36
+ ${mod} interface TestInterface;
37
+ `);
38
+ });
39
+
40
+ it("combines modifiers", () => {
41
+ expect(
42
+ <TestNamespace>
43
+ <InterfaceDeclaration public partial name="TestInterface" />
44
+ </TestNamespace>,
45
+ ).toRenderTo(`
46
+ public partial interface TestInterface;
47
+ `);
48
+ });
49
+ });
50
+
51
+ it("specify doc comment", () => {
52
+ expect(
53
+ <TestNamespace>
54
+ <InterfaceDeclaration name="TestInterface" doc="This is a test" />
55
+ </TestNamespace>,
56
+ ).toRenderTo(`
57
+ /// This is a test
58
+ interface TestInterface;
59
+ `);
60
+ });
61
+
62
+ describe("with type parameters", () => {
63
+ it("reference parameters", () => {
64
+ const typeParameters: TypeParameterProps[] = [
65
+ {
66
+ name: "T",
67
+ refkey: refkey(),
68
+ },
69
+ {
70
+ name: "U",
71
+ refkey: refkey(),
72
+ },
73
+ ];
74
+
75
+ expect(
76
+ <TestNamespace>
77
+ <SourceFile path="Test.cs">
78
+ <InterfaceDeclaration
79
+ public
80
+ name="Test"
81
+ typeParameters={typeParameters}
82
+ >
83
+ <List>
84
+ <InterfaceProperty
85
+ name="PropA"
86
+ type={typeParameters[0].refkey}
87
+ get
88
+ set
89
+ />
90
+ <InterfaceProperty
91
+ name="PropB"
92
+ type={typeParameters[1].refkey}
93
+ get
94
+ set
95
+ />
96
+ </List>
97
+ </InterfaceDeclaration>
98
+ </SourceFile>
99
+ </TestNamespace>,
100
+ ).toRenderTo(`
101
+ namespace TestCode
102
+ {
103
+ public interface Test<T, U>
104
+ {
105
+ T PropA { get; set; }
106
+ U PropB { get; set; }
107
+ }
108
+ }
109
+ `);
110
+ });
111
+
112
+ it("defines with constraints", () => {
113
+ const typeParameters: TypeParameterProps[] = [
114
+ {
115
+ name: "T",
116
+ constraints: "IFoo",
117
+ },
118
+ {
119
+ name: "U",
120
+ constraints: "IBar",
121
+ },
122
+ ];
123
+
124
+ expect(
125
+ <TestNamespace>
126
+ <InterfaceDeclaration
127
+ public
128
+ name="Test"
129
+ typeParameters={typeParameters}
130
+ >
131
+ // Body
132
+ </InterfaceDeclaration>
133
+ </TestNamespace>,
134
+ ).toRenderTo(`
135
+ public interface Test<T, U>
136
+ where T : IFoo
137
+ where U : IBar
138
+ {
139
+ // Body
140
+ }
141
+ `);
142
+ });
143
+ });
@@ -0,0 +1,105 @@
1
+ import * as core from "@alloy-js/core";
2
+ import {
3
+ AccessModifiers,
4
+ computeModifiersPrefix,
5
+ getAccessModifier,
6
+ makeModifiers,
7
+ } from "../../modifiers.js";
8
+ import { useCSharpNamePolicy } from "../../name-policy.js";
9
+ import { CSharpOutputSymbol } from "../../symbols/csharp-output-symbol.js";
10
+ import { CSharpMemberScope } from "../../symbols/scopes.js";
11
+ import { DocWhen } from "../doc/comment.jsx";
12
+ import { Name } from "../Name.jsx";
13
+ import { TypeParameterConstraints } from "../type-parameters/type-parameter-constraints.jsx";
14
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
15
+ import { TypeParameters } from "../type-parameters/type-parameters.jsx";
16
+
17
+ export interface InterfaceModifiers {
18
+ readonly partial?: boolean;
19
+ }
20
+
21
+ const getInterfaceModifiers = makeModifiers<InterfaceModifiers>(["partial"]);
22
+
23
+ // properties for creating a class
24
+ export interface InterfaceDeclarationProps
25
+ extends Omit<core.DeclarationProps, "nameKind">,
26
+ AccessModifiers,
27
+ InterfaceModifiers {
28
+ name: string;
29
+
30
+ /** Doc comment */
31
+ doc?: core.Children;
32
+ refkey?: core.Refkey;
33
+
34
+ /**
35
+ * Type parameters for the interface
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * <InterfaceDeclaration name="IList" typeParameters={["T"]} />
40
+ * ```
41
+ * This will produce:
42
+ * ```csharp
43
+ * public interface IList<T>
44
+ * ```
45
+ */
46
+ typeParameters?: (TypeParameterProps | string)[];
47
+ }
48
+
49
+ /**
50
+ * CSharp interface declaration.
51
+ * @example
52
+ * ```tsx
53
+ * <InterfaceDeclaration public name="IMyInterface">
54
+ * <InterfaceMember public name="MyProperty" type="int" />
55
+ * <InterfaceMethod public name="MyMethod" returnType="void">
56
+ * <Parameter name="value" type="int" />
57
+ * </InterfaceMethod>
58
+ * </InterfaceDeclaration>
59
+ * ```
60
+ * This will produce:
61
+ * ```csharp
62
+ * public interface MyIface
63
+ * {
64
+ * public int MyProperty { get; set; }
65
+ * public void MyMethod(int value);
66
+ * }
67
+ * ```
68
+ */
69
+ export function InterfaceDeclaration(props: InterfaceDeclarationProps) {
70
+ const name = useCSharpNamePolicy().getName(props.name!, "interface");
71
+
72
+ const thisInterfaceSymbol = new CSharpOutputSymbol(name, {
73
+ refkeys: props.refkey,
74
+ });
75
+
76
+ // this creates a new scope for the interface definition.
77
+ // members will automatically "inherit" this scope so
78
+ // that refkeys to them will produce the fully-qualified
79
+ // name e.g. Foo.Bar.
80
+ const thisInterfaceScope = new CSharpMemberScope("interface-decl", {
81
+ owner: thisInterfaceSymbol,
82
+ });
83
+
84
+ const modifiers = computeModifiersPrefix([
85
+ getAccessModifier(props),
86
+ getInterfaceModifiers(props),
87
+ ]);
88
+ return (
89
+ <core.Declaration symbol={thisInterfaceSymbol}>
90
+ <DocWhen doc={props.doc} />
91
+ {modifiers}interface <Name />
92
+ {props.typeParameters && (
93
+ <TypeParameters parameters={props.typeParameters} />
94
+ )}
95
+ {props.typeParameters && (
96
+ <TypeParameterConstraints parameters={props.typeParameters} />
97
+ )}
98
+ {props.children ?
99
+ <core.Block newline>
100
+ <core.Scope value={thisInterfaceScope}>{props.children}</core.Scope>
101
+ </core.Block>
102
+ : ";"}
103
+ </core.Declaration>
104
+ );
105
+ }
@@ -0,0 +1,250 @@
1
+ import { refkey } from "@alloy-js/core";
2
+ import { Children } from "@alloy-js/core/jsx-runtime";
3
+ import { describe, expect, it } from "vitest";
4
+ import { TestNamespace } from "../../../test/utils.jsx";
5
+ import { SourceFile } from "../SourceFile.jsx";
6
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
7
+ import { InterfaceDeclaration } from "./declaration.jsx";
8
+ import { InterfaceMethod } from "./method.jsx";
9
+
10
+ const Wrapper = (props: { children: Children }) => (
11
+ <TestNamespace>
12
+ <InterfaceDeclaration public name="TestInterface">
13
+ {props.children}
14
+ </InterfaceDeclaration>
15
+ </TestNamespace>
16
+ );
17
+
18
+ describe("modifiers", () => {
19
+ describe("access modifiers", () => {
20
+ it.each(["public", "private", "protected", "internal"] as const)(
21
+ "%s",
22
+ (accessModifier) => {
23
+ expect(
24
+ <Wrapper>
25
+ <InterfaceMethod {...{ [accessModifier]: true }} name="MethodOne" />
26
+ </Wrapper>,
27
+ ).toRenderTo(`
28
+ public interface TestInterface
29
+ {
30
+ ${accessModifier} void MethodOne();
31
+ }
32
+ `);
33
+ },
34
+ );
35
+ });
36
+
37
+ describe("method modifiers", () => {
38
+ it.each(["new"] as const)("%s", (methodModifier) => {
39
+ expect(
40
+ <Wrapper>
41
+ <InterfaceMethod {...{ [methodModifier]: true }} name="MethodOne" />
42
+ </Wrapper>,
43
+ ).toRenderTo(`
44
+ public interface TestInterface
45
+ {
46
+ ${methodModifier} void MethodOne();
47
+ }
48
+ `);
49
+ });
50
+ });
51
+
52
+ it("combine modifiers", () => {
53
+ expect(
54
+ <Wrapper>
55
+ <InterfaceMethod returns="Task" public new name="MethodOne" />
56
+ </Wrapper>,
57
+ ).toRenderTo(`
58
+ public interface TestInterface
59
+ {
60
+ public new Task MethodOne();
61
+ }
62
+ `);
63
+ });
64
+ });
65
+
66
+ it("applies PascalCase naming policy", () => {
67
+ expect(
68
+ <Wrapper>
69
+ <InterfaceMethod name="method_one" />
70
+ </Wrapper>,
71
+ ).toRenderTo(`
72
+ public interface TestInterface
73
+ {
74
+ void MethodOne();
75
+ }
76
+ `);
77
+ });
78
+
79
+ it("defines params and return type", () => {
80
+ const params = [
81
+ {
82
+ name: "intParam",
83
+ type: "int",
84
+ },
85
+ {
86
+ name: "stringParam",
87
+ type: "string",
88
+ },
89
+ ];
90
+ const res = (
91
+ <Wrapper>
92
+ <InterfaceMethod
93
+ public
94
+ name="MethodOne"
95
+ parameters={params}
96
+ returns="string"
97
+ />
98
+ </Wrapper>
99
+ );
100
+
101
+ expect(res).toRenderTo(`
102
+ public interface TestInterface
103
+ {
104
+ public string MethodOne(int intParam, string stringParam);
105
+ }
106
+ `);
107
+ });
108
+
109
+ it("defines optional param", () => {
110
+ const res = (
111
+ <Wrapper>
112
+ <InterfaceMethod
113
+ public
114
+ name="MethodOne"
115
+ parameters={[
116
+ {
117
+ name: "intParam",
118
+ type: "int",
119
+ optional: true,
120
+ },
121
+ ]}
122
+ returns="string"
123
+ />
124
+ </Wrapper>
125
+ );
126
+
127
+ expect(res).toRenderTo(`
128
+ public interface TestInterface
129
+ {
130
+ public string MethodOne(int? intParam);
131
+ }
132
+ `);
133
+ });
134
+
135
+ it("defines optional param with default", () => {
136
+ const res = (
137
+ <Wrapper>
138
+ <InterfaceMethod
139
+ public
140
+ name="MethodOne"
141
+ parameters={[
142
+ {
143
+ name: "intParam",
144
+ type: "int",
145
+ default: 12,
146
+ },
147
+ ]}
148
+ returns="string"
149
+ />
150
+ </Wrapper>
151
+ );
152
+
153
+ expect(res).toRenderTo(`
154
+ public interface TestInterface
155
+ {
156
+ public string MethodOne(int intParam = 12);
157
+ }
158
+ `);
159
+ });
160
+
161
+ it("specify doc comment", () => {
162
+ expect(
163
+ <TestNamespace>
164
+ <InterfaceDeclaration name="Test">
165
+ <InterfaceMethod name="Method" doc="This is a test" />
166
+ </InterfaceDeclaration>
167
+ </TestNamespace>,
168
+ ).toRenderTo(`
169
+ interface Test
170
+ {
171
+ /// This is a test
172
+ void Method();
173
+ }
174
+ `);
175
+ });
176
+
177
+ describe("with type parameters", () => {
178
+ it("reference parameters", () => {
179
+ const typeParameters: TypeParameterProps[] = [
180
+ {
181
+ name: "T",
182
+ refkey: refkey(),
183
+ },
184
+ {
185
+ name: "U",
186
+ refkey: refkey(),
187
+ },
188
+ ];
189
+
190
+ expect(
191
+ <TestNamespace>
192
+ <SourceFile path="TestFile.cs">
193
+ <InterfaceDeclaration public name="TestInterface">
194
+ <InterfaceMethod
195
+ name="Test"
196
+ public
197
+ typeParameters={typeParameters}
198
+ parameters={[
199
+ {
200
+ name: "paramA",
201
+ type: typeParameters[0].refkey,
202
+ },
203
+ ]}
204
+ returns={typeParameters[0].refkey}
205
+ />
206
+ </InterfaceDeclaration>
207
+ </SourceFile>
208
+ </TestNamespace>,
209
+ ).toRenderTo(`
210
+ namespace TestCode
211
+ {
212
+ public interface TestInterface
213
+ {
214
+ public T Test<T, U>(T paramA);
215
+ }
216
+ }
217
+ `);
218
+ });
219
+
220
+ it("defines with constraints", () => {
221
+ const typeParameters: TypeParameterProps[] = [
222
+ {
223
+ name: "T",
224
+ constraints: "IFoo",
225
+ },
226
+ {
227
+ name: "U",
228
+ constraints: "IBar",
229
+ },
230
+ ];
231
+
232
+ expect(
233
+ <Wrapper>
234
+ <InterfaceMethod public name="Test" typeParameters={typeParameters}>
235
+ // Body
236
+ </InterfaceMethod>
237
+ </Wrapper>,
238
+ ).toRenderTo(`
239
+ public interface TestInterface
240
+ {
241
+ public void Test<T, U>()
242
+ where T : IFoo
243
+ where U : IBar
244
+ {
245
+ // Body
246
+ }
247
+ }
248
+ `);
249
+ });
250
+ });
@@ -0,0 +1,105 @@
1
+ import {
2
+ Block,
3
+ Children,
4
+ MemberDeclaration,
5
+ refkey,
6
+ Refkey,
7
+ Scope,
8
+ } from "@alloy-js/core";
9
+ import {
10
+ AccessModifiers,
11
+ computeModifiersPrefix,
12
+ getAccessModifier,
13
+ makeModifiers,
14
+ } from "../../modifiers.js";
15
+ import { useCSharpNamePolicy } from "../../name-policy.js";
16
+ import { CSharpOutputSymbol } from "../../symbols/csharp-output-symbol.js";
17
+ import { CSharpMemberScope, useCSharpScope } from "../../symbols/scopes.js";
18
+ import { ParameterProps, Parameters } from "../Parameters.jsx";
19
+ import { DocWhen } from "../doc/comment.jsx";
20
+ import { TypeParameterConstraints } from "../type-parameters/type-parameter-constraints.jsx";
21
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
22
+ import { TypeParameters } from "../type-parameters/type-parameters.jsx";
23
+
24
+ /** Method modifiers. Can only be one. */
25
+ export interface InterfaceMethodModifiers {
26
+ readonly new?: boolean;
27
+ }
28
+
29
+ const getMethodModifier = makeModifiers<InterfaceMethodModifiers>(["new"]);
30
+
31
+ // properties for creating a method
32
+ export interface InterfaceMethodProps
33
+ extends AccessModifiers,
34
+ InterfaceMethodModifiers {
35
+ name: string;
36
+ refkey?: Refkey;
37
+ children?: Children;
38
+ parameters?: Array<ParameterProps>;
39
+ /**
40
+ * Type parameters for the method
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * <InterfaceMethod name="Test" typeParameters={["T"]} />
45
+ * ```
46
+ * This will produce:
47
+ * ```csharp
48
+ * public void Test<T>()
49
+ * ```
50
+ */
51
+ typeParameters?: (TypeParameterProps | string)[];
52
+ returns?: Children;
53
+
54
+ /** Doc comment */
55
+ doc?: Children;
56
+ }
57
+
58
+ // a C# interface method
59
+ export function InterfaceMethod(props: InterfaceMethodProps) {
60
+ const name = useCSharpNamePolicy().getName(props.name, "class-method");
61
+ const scope = useCSharpScope();
62
+ if (scope.kind !== "member" || scope.name !== "interface-decl") {
63
+ throw new Error(
64
+ "can't define an interface method outside of an interface scope",
65
+ );
66
+ }
67
+
68
+ const methodSymbol = new CSharpOutputSymbol(name, {
69
+ scope,
70
+ refkeys: props.refkey ?? refkey(props.name),
71
+ });
72
+
73
+ // scope for method declaration
74
+ const methodScope = new CSharpMemberScope("method-decl", {
75
+ owner: methodSymbol,
76
+ });
77
+
78
+ const params =
79
+ props.parameters ? <Parameters parameters={props.parameters} /> : "";
80
+
81
+ const modifiers = computeModifiersPrefix([
82
+ getAccessModifier(props),
83
+ getMethodModifier(props),
84
+ ]);
85
+ // note that scope wraps the method decl so that the params get the correct scope
86
+ return (
87
+ <MemberDeclaration symbol={methodSymbol}>
88
+ <Scope value={methodScope}>
89
+ <DocWhen doc={props.doc} />
90
+ {modifiers}
91
+ {props.returns ?? "void"} {name}
92
+ {props.typeParameters && (
93
+ <TypeParameters parameters={props.typeParameters} />
94
+ )}
95
+ ({params})
96
+ {props.typeParameters && (
97
+ <TypeParameterConstraints parameters={props.typeParameters} />
98
+ )}
99
+ {props.children ?
100
+ <Block newline>{props.children}</Block>
101
+ : ";"}
102
+ </Scope>
103
+ </MemberDeclaration>
104
+ );
105
+ }