@typespec/emitter-framework 0.9.0-dev.1 → 0.9.0-dev.10

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 (192) hide show
  1. package/dist/src/core/components/output.d.ts +4 -4
  2. package/dist/src/core/components/output.d.ts.map +1 -1
  3. package/dist/src/core/components/output.js +3 -3
  4. package/dist/src/core/context/name-policy-context.d.ts +2 -2
  5. package/dist/src/core/context/name-policy-context.d.ts.map +1 -1
  6. package/dist/src/core/context/tsp-context.d.ts +2 -2
  7. package/dist/src/core/context/tsp-context.d.ts.map +1 -1
  8. package/dist/src/core/transport-name-policy.d.ts +1 -1
  9. package/dist/src/core/transport-name-policy.d.ts.map +1 -1
  10. package/dist/src/core/write-output.d.ts +2 -2
  11. package/dist/src/core/write-output.d.ts.map +1 -1
  12. package/dist/src/csharp/components/class/declaration.d.ts +13 -0
  13. package/dist/src/csharp/components/class/declaration.d.ts.map +1 -0
  14. package/dist/src/csharp/components/class/declaration.js +91 -0
  15. package/dist/src/csharp/components/class/declaration.test.d.ts +2 -0
  16. package/dist/src/csharp/components/class/declaration.test.d.ts.map +1 -0
  17. package/dist/src/csharp/components/class/declaration.test.js +377 -0
  18. package/dist/src/csharp/components/enum/declaration.d.ts +9 -0
  19. package/dist/src/csharp/components/enum/declaration.d.ts.map +1 -0
  20. package/dist/src/csharp/components/enum/declaration.js +55 -0
  21. package/dist/src/csharp/components/enum/declaration.test.d.ts +2 -0
  22. package/dist/src/csharp/components/enum/declaration.test.d.ts.map +1 -0
  23. package/dist/src/csharp/components/enum/declaration.test.js +309 -0
  24. package/dist/src/csharp/components/index.d.ts +5 -0
  25. package/dist/src/csharp/components/index.d.ts.map +1 -0
  26. package/dist/src/csharp/components/index.js +4 -0
  27. package/dist/src/csharp/components/property/property.d.ts +15 -0
  28. package/dist/src/csharp/components/property/property.d.ts.map +1 -0
  29. package/dist/src/csharp/components/property/property.js +85 -0
  30. package/dist/src/csharp/components/property/property.test.d.ts +2 -0
  31. package/dist/src/csharp/components/property/property.test.d.ts.map +1 -0
  32. package/dist/src/csharp/components/property/property.test.js +117 -0
  33. package/dist/src/csharp/components/type-expression.d.ts +11 -0
  34. package/dist/src/csharp/components/type-expression.d.ts.map +1 -0
  35. package/dist/src/csharp/components/type-expression.js +143 -0
  36. package/dist/src/csharp/components/type-expression.test.d.ts +2 -0
  37. package/dist/src/csharp/components/type-expression.test.d.ts.map +1 -0
  38. package/dist/src/csharp/components/type-expression.test.js +128 -0
  39. package/dist/src/csharp/components/utils/doc-comments.d.ts +14 -0
  40. package/dist/src/csharp/components/utils/doc-comments.d.ts.map +1 -0
  41. package/dist/src/csharp/components/utils/doc-comments.js +67 -0
  42. package/dist/src/csharp/components/utils/refkey.d.ts +23 -0
  43. package/dist/src/csharp/components/utils/refkey.d.ts.map +1 -0
  44. package/dist/src/csharp/components/utils/refkey.js +35 -0
  45. package/dist/src/csharp/index.d.ts +2 -0
  46. package/dist/src/csharp/index.d.ts.map +1 -0
  47. package/dist/src/csharp/index.js +1 -0
  48. package/dist/src/testing/index.d.ts +1 -1
  49. package/dist/src/testing/index.d.ts.map +1 -1
  50. package/dist/src/testing/scenario-test/code-block-expectation.d.ts +33 -0
  51. package/dist/src/testing/scenario-test/code-block-expectation.d.ts.map +1 -0
  52. package/dist/src/testing/scenario-test/code-block-expectation.js +69 -0
  53. package/dist/src/testing/scenario-test/code-block-expectation.test.d.ts +2 -0
  54. package/dist/src/testing/scenario-test/code-block-expectation.test.d.ts.map +1 -0
  55. package/dist/src/testing/scenario-test/code-block-expectation.test.js +80 -0
  56. package/dist/src/testing/scenario-test/harness.d.ts +3 -3
  57. package/dist/src/testing/scenario-test/harness.d.ts.map +1 -1
  58. package/dist/src/testing/scenario-test/harness.js +69 -158
  59. package/dist/src/testing/scenario-test/index.d.ts +0 -1
  60. package/dist/src/testing/scenario-test/index.d.ts.map +1 -1
  61. package/dist/src/testing/scenario-test/index.js +1 -2
  62. package/dist/src/testing/scenario-test/snippet-extractor.d.ts +1 -1
  63. package/dist/src/testing/scenario-test/snippet-extractor.js +1 -1
  64. package/dist/src/typescript/components/array-expression.d.ts +2 -3
  65. package/dist/src/typescript/components/array-expression.d.ts.map +1 -1
  66. package/dist/src/typescript/components/array-expression.js +2 -2
  67. package/dist/src/typescript/components/arrow-function.d.ts +2 -2
  68. package/dist/src/typescript/components/arrow-function.d.ts.map +1 -1
  69. package/dist/src/typescript/components/arrow-function.js +2 -1
  70. package/dist/src/typescript/components/class-method.d.ts +1 -1
  71. package/dist/src/typescript/components/class-method.d.ts.map +1 -1
  72. package/dist/src/typescript/components/enum-declaration.d.ts +6 -6
  73. package/dist/src/typescript/components/enum-declaration.d.ts.map +1 -1
  74. package/dist/src/typescript/components/enum-declaration.js +2 -2
  75. package/dist/src/typescript/components/function-declaration.d.ts +1 -1
  76. package/dist/src/typescript/components/function-declaration.d.ts.map +1 -1
  77. package/dist/src/typescript/components/function-expression.d.ts +2 -2
  78. package/dist/src/typescript/components/function-expression.d.ts.map +1 -1
  79. package/dist/src/typescript/components/function-expression.js +2 -1
  80. package/dist/src/typescript/components/function-type.d.ts +2 -2
  81. package/dist/src/typescript/components/function-type.d.ts.map +1 -1
  82. package/dist/src/typescript/components/function-type.js +2 -1
  83. package/dist/src/typescript/components/interface-declaration.d.ts +4 -4
  84. package/dist/src/typescript/components/interface-declaration.d.ts.map +1 -1
  85. package/dist/src/typescript/components/interface-declaration.js +3 -4
  86. package/dist/src/typescript/components/interface-member.d.ts +2 -2
  87. package/dist/src/typescript/components/interface-member.d.ts.map +1 -1
  88. package/dist/src/typescript/components/interface-method.d.ts +2 -2
  89. package/dist/src/typescript/components/interface-method.d.ts.map +1 -1
  90. package/dist/src/typescript/components/record-expression.d.ts +1 -1
  91. package/dist/src/typescript/components/record-expression.d.ts.map +1 -1
  92. package/dist/src/typescript/components/type-alias-declaration.d.ts +1 -1
  93. package/dist/src/typescript/components/type-alias-declaration.d.ts.map +1 -1
  94. package/dist/src/typescript/components/type-declaration.d.ts +1 -1
  95. package/dist/src/typescript/components/type-declaration.d.ts.map +1 -1
  96. package/dist/src/typescript/components/type-expression.d.ts +1 -1
  97. package/dist/src/typescript/components/type-expression.d.ts.map +1 -1
  98. package/dist/src/typescript/components/type-transform.d.ts +2 -2
  99. package/dist/src/typescript/components/type-transform.d.ts.map +1 -1
  100. package/dist/src/typescript/components/union-declaration.d.ts +2 -2
  101. package/dist/src/typescript/components/union-declaration.d.ts.map +1 -1
  102. package/dist/src/typescript/components/union-expression.d.ts +3 -4
  103. package/dist/src/typescript/components/union-expression.d.ts.map +1 -1
  104. package/dist/src/typescript/components/union-expression.js +3 -3
  105. package/dist/src/typescript/components/value-expression.d.ts +2 -2
  106. package/dist/src/typescript/components/value-expression.d.ts.map +1 -1
  107. package/dist/src/typescript/utils/operation.d.ts +2 -2
  108. package/dist/src/typescript/utils/operation.d.ts.map +1 -1
  109. package/dist/test/test-host.d.ts +2 -0
  110. package/dist/test/test-host.d.ts.map +1 -0
  111. package/dist/test/test-host.js +5 -0
  112. package/dist/test/testing/snippet-extractor-csharp.test.js +3 -3
  113. package/dist/test/testing/snippet-extractor-java.test.js +3 -3
  114. package/dist/test/testing/snippet-extractor-python.test.js +2 -2
  115. package/dist/test/testing/snippet-extractor-typescript.test.js +3 -3
  116. package/dist/test/typescript/components/member-expression.test.js +5 -5
  117. package/dist/test/typescript/test-host.d.ts +1 -1
  118. package/dist/test/typescript/test-host.d.ts.map +1 -1
  119. package/dist/test/utils.d.ts +2 -2
  120. package/dist/test/utils.d.ts.map +1 -1
  121. package/dist/test/vitest.setup.d.ts +2 -0
  122. package/dist/test/vitest.setup.d.ts.map +1 -0
  123. package/dist/test/vitest.setup.js +1 -0
  124. package/package.json +26 -8
  125. package/src/core/components/output.tsx +9 -5
  126. package/src/core/context/name-policy-context.ts +2 -2
  127. package/src/core/context/tsp-context.ts +2 -2
  128. package/src/core/transport-name-policy.ts +1 -1
  129. package/src/core/write-output.ts +2 -2
  130. package/src/csharp/components/class/declaration.test.tsx +339 -0
  131. package/src/csharp/components/class/declaration.tsx +86 -0
  132. package/src/csharp/components/enum/declaration.test.tsx +267 -0
  133. package/src/csharp/components/enum/declaration.tsx +56 -0
  134. package/src/csharp/components/index.ts +4 -0
  135. package/src/csharp/components/property/property.test.tsx +97 -0
  136. package/src/csharp/components/property/property.tsx +62 -0
  137. package/src/csharp/components/type-expression.test.tsx +133 -0
  138. package/src/csharp/components/type-expression.tsx +119 -0
  139. package/src/csharp/components/utils/doc-comments.tsx +58 -0
  140. package/src/csharp/components/utils/refkey.ts +36 -0
  141. package/src/csharp/index.ts +1 -0
  142. package/src/testing/index.ts +1 -1
  143. package/src/testing/scenario-test/code-block-expectation.test.ts +95 -0
  144. package/src/testing/scenario-test/code-block-expectation.ts +115 -0
  145. package/src/testing/scenario-test/harness.ts +92 -237
  146. package/src/testing/scenario-test/index.ts +0 -1
  147. package/src/testing/scenario-test/snippet-extractor.ts +1 -1
  148. package/src/typescript/components/array-expression.tsx +3 -3
  149. package/src/typescript/components/arrow-function.tsx +2 -2
  150. package/src/typescript/components/class-method.tsx +1 -1
  151. package/src/typescript/components/enum-declaration.tsx +6 -6
  152. package/src/typescript/components/function-declaration.tsx +1 -1
  153. package/src/typescript/components/function-expression.tsx +2 -2
  154. package/src/typescript/components/function-type.tsx +2 -2
  155. package/src/typescript/components/interface-declaration.tsx +11 -12
  156. package/src/typescript/components/interface-member.tsx +2 -2
  157. package/src/typescript/components/interface-method.tsx +2 -2
  158. package/src/typescript/components/record-expression.tsx +1 -1
  159. package/src/typescript/components/type-alias-declaration.tsx +1 -1
  160. package/src/typescript/components/type-declaration.tsx +1 -1
  161. package/src/typescript/components/type-expression.tsx +2 -2
  162. package/src/typescript/components/type-transform.tsx +3 -3
  163. package/src/typescript/components/union-declaration.tsx +2 -2
  164. package/src/typescript/components/union-expression.tsx +12 -7
  165. package/src/typescript/components/value-expression.tsx +2 -2
  166. package/src/typescript/utils/operation.ts +2 -2
  167. package/test/test-host.ts +4 -0
  168. package/test/testing/snippet-extractor-csharp.test.ts +4 -4
  169. package/test/testing/snippet-extractor-java.test.ts +4 -4
  170. package/test/testing/snippet-extractor-python.test.ts +3 -3
  171. package/test/testing/snippet-extractor-typescript.test.ts +4 -4
  172. package/test/typescript/components/arrow-function.test.tsx +2 -2
  173. package/test/typescript/components/enum-declaration.test.tsx +1 -1
  174. package/test/typescript/components/function-declaration.test.tsx +1 -1
  175. package/test/typescript/components/function-expression.test.tsx +2 -2
  176. package/test/typescript/components/function-type.test.tsx +2 -2
  177. package/test/typescript/components/interface-declaration.test.tsx +1 -1
  178. package/test/typescript/components/interface-method.test.tsx +2 -2
  179. package/test/typescript/components/member-expression.test.tsx +10 -10
  180. package/test/typescript/components/type-alias-declaration.test.tsx +1 -1
  181. package/test/typescript/components/type-transform.test.tsx +2 -2
  182. package/test/typescript/components/union-declaration.test.tsx +2 -2
  183. package/test/typescript/components/value-expression.test.tsx +6 -6
  184. package/test/typescript/test-host.ts +1 -1
  185. package/test/utils.ts +2 -2
  186. package/test/vitest.setup.ts +1 -0
  187. package/tsconfig.json +3 -1
  188. package/vitest.config.ts +2 -1
  189. package/dist/src/testing/scenario-test/test-host.d.ts +0 -8
  190. package/dist/src/testing/scenario-test/test-host.d.ts.map +0 -1
  191. package/dist/src/testing/scenario-test/test-host.js +0 -49
  192. package/src/testing/scenario-test/test-host.ts +0 -83
@@ -0,0 +1,339 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { type Children } from "@alloy-js/core";
3
+ import { createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
4
+ import { t, type TesterInstance } from "@typespec/compiler/testing";
5
+ import { beforeEach, describe, expect, it } from "vitest";
6
+ import { Output } from "../../../core/index.js";
7
+ import { ClassDeclaration, EnumDeclaration } from "../../index.js";
8
+
9
+ let runner: TesterInstance;
10
+
11
+ beforeEach(async () => {
12
+ runner = await Tester.createInstance();
13
+ });
14
+
15
+ function Wrapper(props: { children: Children }) {
16
+ const policy = createCSharpNamePolicy();
17
+ return (
18
+ <Output program={runner.program} namePolicy={policy}>
19
+ <Namespace name="TestNamespace">
20
+ <SourceFile path="test.cs">{props.children}</SourceFile>
21
+ </Namespace>
22
+ </Output>
23
+ );
24
+ }
25
+
26
+ it("renders an empty class declaration", async () => {
27
+ const { TestModel } = await runner.compile(t.code`
28
+ model ${t.model("TestModel")} {}
29
+ `);
30
+
31
+ expect(
32
+ <Wrapper>
33
+ <ClassDeclaration type={TestModel} />
34
+ </Wrapper>,
35
+ ).toRenderTo(`
36
+ namespace TestNamespace
37
+ {
38
+ class TestModel
39
+ {
40
+
41
+ }
42
+ }
43
+ `);
44
+ });
45
+
46
+ it("renders a class declaration with properties", async () => {
47
+ const { TestModel } = await runner.compile(t.code`
48
+ model ${t.model("TestModel")} {
49
+ @test Prop1: string;
50
+ @test Prop2: int32;
51
+ }
52
+ `);
53
+
54
+ expect(
55
+ <Wrapper>
56
+ <ClassDeclaration type={TestModel} />
57
+ </Wrapper>,
58
+ ).toRenderTo(`
59
+ namespace TestNamespace
60
+ {
61
+ class TestModel
62
+ {
63
+ public required string Prop1 { get; set; }
64
+ public required int Prop2 { get; set; }
65
+ }
66
+ }
67
+ `);
68
+ });
69
+
70
+ it("can override class name", async () => {
71
+ const { TestModel } = await runner.compile(t.code`
72
+ model ${t.model("TestModel")} {}
73
+ `);
74
+
75
+ expect(
76
+ <Wrapper>
77
+ <ClassDeclaration type={TestModel} name="CustomClassName" />
78
+ </Wrapper>,
79
+ ).toRenderTo(`
80
+ namespace TestNamespace
81
+ {
82
+ class CustomClassName
83
+ {
84
+
85
+ }
86
+ }
87
+ `);
88
+ });
89
+
90
+ it("renders a class with access modifiers", async () => {
91
+ const { TestModel } = await runner.compile(t.code`
92
+ model ${t.model("TestModel")} {
93
+ }
94
+ `);
95
+
96
+ expect(
97
+ <Wrapper>
98
+ <ClassDeclaration type={TestModel} protected />
99
+ </Wrapper>,
100
+ ).toRenderTo(`
101
+ namespace TestNamespace
102
+ {
103
+ protected class TestModel
104
+ {
105
+
106
+ }
107
+ }
108
+ `);
109
+ });
110
+
111
+ describe("from an interface", () => {
112
+ it("renders an empty class", async () => {
113
+ const { TestInterface } = await runner.compile(t.code`
114
+ interface ${t.interface("TestInterface")} {
115
+ }
116
+ `);
117
+
118
+ expect(
119
+ <Wrapper>
120
+ <ClassDeclaration type={TestInterface} />
121
+ </Wrapper>,
122
+ ).toRenderTo(`
123
+ namespace TestNamespace
124
+ {
125
+ class TestInterface
126
+ {
127
+
128
+ }
129
+ }
130
+ `);
131
+ });
132
+
133
+ it("renders a class with operations", async () => {
134
+ const { TestInterface } = await runner.compile(t.code`
135
+ interface ${t.interface("TestInterface")} {
136
+ op getName(id: string): string;
137
+ }
138
+ `);
139
+
140
+ expect(
141
+ <Wrapper>
142
+ <ClassDeclaration type={TestInterface} />
143
+ </Wrapper>,
144
+ ).toRenderTo(`
145
+ namespace TestNamespace
146
+ {
147
+ class TestInterface
148
+ {
149
+ public abstract string GetName(string id);
150
+ }
151
+ }
152
+ `);
153
+ });
154
+ });
155
+
156
+ it("renders a class with model members", async () => {
157
+ const { TestModel, TestReference } = await runner.compile(t.code`
158
+ model ${t.model("TestReference")} { }
159
+ model ${t.model("TestModel")} {
160
+ prop1: TestReference;
161
+ }
162
+ `);
163
+
164
+ expect(
165
+ <Wrapper>
166
+ <ClassDeclaration type={TestReference} />
167
+ <hbr />
168
+ <ClassDeclaration type={TestModel} />
169
+ </Wrapper>,
170
+ ).toRenderTo(`
171
+ namespace TestNamespace
172
+ {
173
+ class TestReference
174
+ {
175
+
176
+ }
177
+ class TestModel
178
+ {
179
+ public required TestReference Prop1 { get; set; }
180
+ }
181
+ }
182
+ `);
183
+ });
184
+
185
+ it("renders a class with enum members", async () => {
186
+ const { TestModel, TestEnum } = await runner.compile(t.code`
187
+ @test enum ${t.enum("TestEnum")} {
188
+ Value1;
189
+ Value2;
190
+ }
191
+ model ${t.model("TestModel")} {
192
+ @test prop1: TestEnum;
193
+ }
194
+ `);
195
+
196
+ expect(
197
+ <Wrapper>
198
+ <EnumDeclaration type={TestEnum} />
199
+ <hbr />
200
+ <ClassDeclaration type={TestModel} />
201
+ </Wrapper>,
202
+ ).toRenderTo(`
203
+ namespace TestNamespace
204
+ {
205
+ enum TestEnum
206
+ {
207
+ Value1,
208
+ Value2
209
+ }
210
+ class TestModel
211
+ {
212
+ public required TestEnum Prop1 { get; set; }
213
+ }
214
+ }
215
+ `);
216
+ });
217
+
218
+ it("maps prop: string | null to nullable property", async () => {
219
+ const { TestModel } = await runner.compile(t.code`
220
+ model ${t.model("TestModel")} {
221
+ prop1: string | null;
222
+ }
223
+ `);
224
+
225
+ expect(
226
+ <Wrapper>
227
+ <ClassDeclaration type={TestModel} />
228
+ </Wrapper>,
229
+ ).toRenderTo(`
230
+ namespace TestNamespace
231
+ {
232
+ class TestModel
233
+ {
234
+ public required string? Prop1 { get; set; }
235
+ }
236
+ }
237
+ `);
238
+ });
239
+
240
+ it("renders a class with string enums", async () => {
241
+ const { TestModel, TestEnum } = await runner.compile(t.code`
242
+ @test enum ${t.enum("TestEnum")} {
243
+ Value1;
244
+ Value2;
245
+ }
246
+ model ${t.model("TestModel")} {
247
+ @test prop1: TestEnum;
248
+ }
249
+ `);
250
+
251
+ expect(
252
+ <Wrapper>
253
+ <EnumDeclaration type={TestEnum} />
254
+ <hbr />
255
+ <ClassDeclaration type={TestModel} />
256
+ </Wrapper>,
257
+ ).toRenderTo(`
258
+ namespace TestNamespace
259
+ {
260
+ enum TestEnum
261
+ {
262
+ Value1,
263
+ Value2
264
+ }
265
+ class TestModel
266
+ {
267
+ public required TestEnum Prop1 { get; set; }
268
+ }
269
+ }
270
+ `);
271
+ });
272
+
273
+ describe("with doc comments", () => {
274
+ it("renders a model with docs", async () => {
275
+ const { TestModel } = await runner.compile(t.code`
276
+ @doc("This is a test model")
277
+ model ${t.model("TestModel")} {
278
+ @doc("This is a test property")
279
+ prop1: string;
280
+ }
281
+
282
+ `);
283
+
284
+ expect(
285
+ <Wrapper>
286
+ <ClassDeclaration type={TestModel} />
287
+ </Wrapper>,
288
+ ).toRenderTo(`
289
+ namespace TestNamespace
290
+ {
291
+ /// <summary>
292
+ /// This is a test model
293
+ /// </summary>
294
+ class TestModel
295
+ {
296
+ /// <summary>
297
+ /// This is a test property
298
+ /// </summary>
299
+ public required string Prop1 { get; set; }
300
+ }
301
+ }
302
+ `);
303
+ });
304
+
305
+ it("renders an interface with docs", async () => {
306
+ const { TestInterface } = await runner.compile(t.code`
307
+ @doc("This is a test interface")
308
+ @test interface ${t.interface("TestInterface")} {
309
+ @doc("This is a test operation")
310
+ @returnsDoc("The name of the item")
311
+ op getName(id: string): string;
312
+ }
313
+ `);
314
+
315
+ expect(
316
+ <Wrapper>
317
+ <ClassDeclaration type={TestInterface} />
318
+ </Wrapper>,
319
+ ).toRenderTo(`
320
+ namespace TestNamespace
321
+ {
322
+ /// <summary>
323
+ /// This is a test interface
324
+ /// </summary>
325
+ class TestInterface
326
+ {
327
+ /// <summary>
328
+ /// This is a test operation
329
+ /// </summary>
330
+ ///
331
+ /// <returns>
332
+ /// The name of the item
333
+ /// </returns>
334
+ public abstract string GetName(string id);
335
+ }
336
+ }
337
+ `);
338
+ });
339
+ });
@@ -0,0 +1,86 @@
1
+ import { type Children, For } from "@alloy-js/core";
2
+ import * as cs from "@alloy-js/csharp";
3
+ import type { Interface, Model } from "@typespec/compiler";
4
+ import { useTsp } from "../../../core/index.js";
5
+ import { Property } from "../property/property.jsx";
6
+ import { TypeExpression } from "../type-expression.jsx";
7
+ import { getDocComments } from "../utils/doc-comments.jsx";
8
+ import { declarationRefkeys } from "../utils/refkey.js";
9
+
10
+ export interface ClassDeclarationProps extends Omit<cs.ClassDeclarationProps, "name"> {
11
+ /** Set an alternative name for the class. Otherwise default to the type name. */
12
+ name?: string;
13
+ /** Type to use to create this class. */
14
+ type: Model | Interface;
15
+ /** If set the property will add the json serialization attributes(using System.Text.Json). */
16
+ jsonAttributes?: boolean;
17
+ }
18
+
19
+ interface ClassPropertiesProps {
20
+ type: Model;
21
+ /** If set the property will add the json serialization attributes(using System.Text.Json). */
22
+ jsonAttributes?: boolean;
23
+ }
24
+
25
+ interface ClassMethodsProps {
26
+ type: Interface;
27
+ }
28
+
29
+ export function ClassDeclaration(props: ClassDeclarationProps): Children {
30
+ const { $ } = useTsp();
31
+
32
+ const namePolicy = cs.useCSharpNamePolicy();
33
+ const className = props.name ?? namePolicy.getName(props.type.name, "class");
34
+
35
+ const refkeys = declarationRefkeys(props.refkey, props.type)[0]; // TODO: support multiple refkeys for declarations in alloy
36
+
37
+ return (
38
+ <>
39
+ <cs.ClassDeclaration
40
+ {...props}
41
+ name={className}
42
+ refkey={refkeys}
43
+ doc={getDocComments($, props.type)}
44
+ >
45
+ {props.type.kind === "Model" && (
46
+ <ClassProperties type={props.type} jsonAttributes={props.jsonAttributes} />
47
+ )}
48
+ {props.type.kind === "Interface" && <ClassMethods type={props.type} />}
49
+ </cs.ClassDeclaration>
50
+ </>
51
+ );
52
+ }
53
+
54
+ function ClassProperties(props: ClassPropertiesProps): Children {
55
+ return (
56
+ <For each={props.type.properties.entries()} hardline>
57
+ {([name, property]) => <Property type={property} jsonAttributes={props.jsonAttributes} />}
58
+ </For>
59
+ );
60
+ }
61
+
62
+ function ClassMethods(props: ClassMethodsProps): Children {
63
+ const { $ } = useTsp();
64
+ const namePolicy = cs.useCSharpNamePolicy();
65
+
66
+ const abstractMethods: Children = [];
67
+ for (const [name, method] of props.type.operations) {
68
+ abstractMethods.push(
69
+ <cs.ClassMethod
70
+ name={namePolicy.getName(name, "class-method")}
71
+ abstract
72
+ parameters={[...method.parameters.properties.entries()].map(([name, prop]) => {
73
+ return {
74
+ name: namePolicy.getName(name, "type-parameter"),
75
+ type: <TypeExpression type={prop.type} />,
76
+ };
77
+ })}
78
+ public
79
+ doc={getDocComments($, method)}
80
+ returns={<TypeExpression type={method.returnType} />}
81
+ />,
82
+ );
83
+ }
84
+
85
+ return <>{abstractMethods}</>;
86
+ }
@@ -0,0 +1,267 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { type Children } from "@alloy-js/core";
3
+ import { createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
4
+ import { t, type TesterInstance } from "@typespec/compiler/testing";
5
+ import { beforeEach, expect, it } from "vitest";
6
+ import { Output } from "../../../core/index.js";
7
+ import { EnumDeclaration } from "../../index.js";
8
+
9
+ let runner: TesterInstance;
10
+
11
+ beforeEach(async () => {
12
+ runner = await Tester.createInstance();
13
+ });
14
+
15
+ function Wrapper(props: { children: Children }) {
16
+ const policy = createCSharpNamePolicy();
17
+ return (
18
+ <Output program={runner.program} namePolicy={policy}>
19
+ <Namespace name="TestNamespace">
20
+ <SourceFile path="test.cs">{props.children}</SourceFile>
21
+ </Namespace>
22
+ </Output>
23
+ );
24
+ }
25
+
26
+ it("renders a basic enum declaration", async () => {
27
+ const { TestEnum } = await runner.compile(t.code`
28
+ @test enum ${t.enum("TestEnum")} {
29
+ Value1;
30
+ Value2;
31
+ Value3;
32
+ }
33
+ `);
34
+
35
+ expect(
36
+ <Wrapper>
37
+ <EnumDeclaration type={TestEnum} />
38
+ </Wrapper>,
39
+ ).toRenderTo(`
40
+ namespace TestNamespace
41
+ {
42
+ enum TestEnum
43
+ {
44
+ Value1,
45
+ Value2,
46
+ Value3
47
+ }
48
+ }
49
+ `);
50
+ });
51
+
52
+ it("renders an empty enum declaration", async () => {
53
+ const { TestEnum } = await runner.compile(t.code`
54
+ @test enum ${t.enum("TestEnum")} {}
55
+ `);
56
+
57
+ expect(
58
+ <Wrapper>
59
+ <EnumDeclaration type={TestEnum} />
60
+ </Wrapper>,
61
+ ).toRenderTo(`
62
+ namespace TestNamespace
63
+ {
64
+ enum TestEnum
65
+ {
66
+
67
+ }
68
+ }
69
+ `);
70
+ });
71
+
72
+ it("can override enum name", async () => {
73
+ const { TestEnum } = await runner.compile(t.code`
74
+ @test enum ${t.enum("TestEnum")} {
75
+ Value1;
76
+ Value2;
77
+ }
78
+ `);
79
+
80
+ expect(
81
+ <Wrapper>
82
+ <EnumDeclaration type={TestEnum} name="CustomEnumName" />
83
+ </Wrapper>,
84
+ ).toRenderTo(`
85
+ namespace TestNamespace
86
+ {
87
+ enum CustomEnumName
88
+ {
89
+ Value1,
90
+ Value2
91
+ }
92
+ }
93
+ `);
94
+ });
95
+
96
+ it("renders an enum with access modifiers", async () => {
97
+ const { TestEnum } = await runner.compile(t.code`
98
+ @test enum ${t.enum("TestEnum")} {
99
+ Value1;
100
+ Value2;
101
+ }
102
+ `);
103
+
104
+ expect(
105
+ <Wrapper>
106
+ <EnumDeclaration type={TestEnum} internal />
107
+ </Wrapper>,
108
+ ).toRenderTo(`
109
+ namespace TestNamespace
110
+ {
111
+ internal enum TestEnum
112
+ {
113
+ Value1,
114
+ Value2
115
+ }
116
+ }
117
+ `);
118
+ });
119
+
120
+ it("renders enum with C# naming conventions", async () => {
121
+ const { TestEnum } = await runner.compile(t.code`
122
+ @test enum ${t.enum("TestEnum")} {
123
+ value_one;
124
+ value_two;
125
+ value_three;
126
+ }
127
+ `);
128
+
129
+ expect(
130
+ <Output program={runner.program} namePolicy={createCSharpNamePolicy()}>
131
+ <Namespace name="TestNamespace">
132
+ <SourceFile path="test.cs">
133
+ <EnumDeclaration type={TestEnum} />
134
+ </SourceFile>
135
+ </Namespace>
136
+ </Output>,
137
+ ).toRenderTo(`
138
+ namespace TestNamespace
139
+ {
140
+ enum TestEnum
141
+ {
142
+ ValueOne,
143
+ ValueTwo,
144
+ ValueThree
145
+ }
146
+ }
147
+ `);
148
+ });
149
+
150
+ it("renders enum with single value", async () => {
151
+ const { TestEnum } = await runner.compile(t.code`
152
+ @test enum ${t.enum("TestEnum")} {
153
+ OnlyValue;
154
+ }
155
+ `);
156
+
157
+ expect(
158
+ <Wrapper>
159
+ <EnumDeclaration type={TestEnum} />
160
+ </Wrapper>,
161
+ ).toRenderTo(`
162
+ namespace TestNamespace
163
+ {
164
+ enum TestEnum
165
+ {
166
+ OnlyValue
167
+ }
168
+ }
169
+ `);
170
+ });
171
+
172
+ it("renders enum with numeric-like member names", async () => {
173
+ const { TestEnum } = await runner.compile(t.code`
174
+ @test enum ${t.enum("TestEnum")} {
175
+ Value0;
176
+ Value1;
177
+ Value10;
178
+ Value100;
179
+ }
180
+ `);
181
+
182
+ expect(
183
+ <Wrapper>
184
+ <EnumDeclaration type={TestEnum} />
185
+ </Wrapper>,
186
+ ).toRenderTo(`
187
+ namespace TestNamespace
188
+ {
189
+ enum TestEnum
190
+ {
191
+ Value0,
192
+ Value1,
193
+ Value10,
194
+ Value100
195
+ }
196
+ }
197
+ `);
198
+ });
199
+
200
+ it("renders multiple enums in the same namespace", async () => {
201
+ const { TestEnum1, TestEnum2 } = await runner.compile(t.code`
202
+ @test enum ${t.enum("TestEnum1")} {
203
+ Value1;
204
+ Value2;
205
+ }
206
+ @test enum ${t.enum("TestEnum2")} {
207
+ OptionA;
208
+ OptionB;
209
+ OptionC;
210
+ }
211
+ `);
212
+
213
+ expect(
214
+ <Wrapper>
215
+ <EnumDeclaration type={TestEnum1} />
216
+ <hbr />
217
+ <EnumDeclaration type={TestEnum2} />
218
+ </Wrapper>,
219
+ ).toRenderTo(`
220
+ namespace TestNamespace
221
+ {
222
+ enum TestEnum1
223
+ {
224
+ Value1,
225
+ Value2
226
+ }
227
+ enum TestEnum2
228
+ {
229
+ OptionA,
230
+ OptionB,
231
+ OptionC
232
+ }
233
+ }
234
+ `);
235
+ });
236
+
237
+ it("renders an enum with doc comments", async () => {
238
+ const { TestEnum } = await runner.compile(t.code`
239
+ @test enum ${t.enum("TestEnum")} {
240
+ @doc("This is value one")
241
+ Value1;
242
+ /** This is value two */
243
+ Value2;
244
+ }
245
+ `);
246
+
247
+ expect(
248
+ <Wrapper>
249
+ <EnumDeclaration type={TestEnum} />
250
+ </Wrapper>,
251
+ ).toRenderTo(`
252
+ namespace TestNamespace
253
+ {
254
+ enum TestEnum
255
+ {
256
+ /// <summary>
257
+ /// This is value one
258
+ /// </summary>
259
+ Value1,
260
+ /// <summary>
261
+ /// This is value two
262
+ /// </summary>
263
+ Value2
264
+ }
265
+ }
266
+ `);
267
+ });