@typespec/emitter-framework 0.9.0-dev.3 → 0.9.0-dev.6

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 (67) hide show
  1. package/dist/src/csharp/components/class/declaration.d.ts +13 -0
  2. package/dist/src/csharp/components/class/declaration.d.ts.map +1 -0
  3. package/dist/src/csharp/components/{class-declaration.js → class/declaration.js} +35 -41
  4. package/dist/src/csharp/components/class/declaration.test.d.ts +2 -0
  5. package/dist/src/csharp/components/class/declaration.test.d.ts.map +1 -0
  6. package/dist/src/csharp/components/class/declaration.test.js +392 -0
  7. package/dist/src/csharp/components/enum-declaration.d.ts +1 -1
  8. package/dist/src/csharp/components/enum-declaration.d.ts.map +1 -1
  9. package/dist/src/csharp/components/enum-declaration.js +12 -9
  10. package/dist/src/csharp/components/index.d.ts +2 -1
  11. package/dist/src/csharp/components/index.d.ts.map +1 -1
  12. package/dist/src/csharp/components/index.js +2 -1
  13. package/dist/src/csharp/components/property/property.d.ts +15 -0
  14. package/dist/src/csharp/components/property/property.d.ts.map +1 -0
  15. package/dist/src/csharp/components/property/property.js +85 -0
  16. package/dist/src/csharp/components/property/property.test.d.ts +2 -0
  17. package/dist/src/csharp/components/property/property.test.d.ts.map +1 -0
  18. package/dist/src/csharp/components/property/property.test.js +117 -0
  19. package/dist/src/csharp/components/type-expression.d.ts.map +1 -1
  20. package/dist/src/csharp/components/type-expression.js +15 -1
  21. package/dist/src/csharp/components/type-expression.test.d.ts +2 -0
  22. package/dist/src/csharp/components/type-expression.test.d.ts.map +1 -0
  23. package/dist/src/csharp/components/type-expression.test.js +128 -0
  24. package/dist/src/csharp/components/utils/doc-comments.d.ts +14 -0
  25. package/dist/src/csharp/components/utils/doc-comments.d.ts.map +1 -0
  26. package/dist/src/csharp/components/utils/doc-comments.js +67 -0
  27. package/dist/src/typescript/components/arrow-function.d.ts +1 -1
  28. package/dist/src/typescript/components/arrow-function.d.ts.map +1 -1
  29. package/dist/src/typescript/components/arrow-function.js +2 -1
  30. package/dist/src/typescript/components/function-expression.d.ts +1 -1
  31. package/dist/src/typescript/components/function-expression.d.ts.map +1 -1
  32. package/dist/src/typescript/components/function-expression.js +2 -1
  33. package/dist/src/typescript/components/function-type.d.ts +1 -1
  34. package/dist/src/typescript/components/function-type.d.ts.map +1 -1
  35. package/dist/src/typescript/components/function-type.js +2 -1
  36. package/dist/test/csharp/components/enum-declaration.test.js +57 -9
  37. package/dist/test/test-host.d.ts +2 -0
  38. package/dist/test/test-host.d.ts.map +1 -0
  39. package/dist/test/test-host.js +5 -0
  40. package/dist/test/vitest.setup.d.ts +2 -0
  41. package/dist/test/vitest.setup.d.ts.map +1 -0
  42. package/dist/test/vitest.setup.js +1 -0
  43. package/package.json +10 -7
  44. package/src/csharp/components/class/declaration.test.tsx +401 -0
  45. package/src/csharp/components/class/declaration.tsx +86 -0
  46. package/src/csharp/components/enum-declaration.tsx +23 -15
  47. package/src/csharp/components/index.ts +2 -1
  48. package/src/csharp/components/property/property.test.tsx +97 -0
  49. package/src/csharp/components/property/property.tsx +62 -0
  50. package/src/csharp/components/type-expression.test.tsx +133 -0
  51. package/src/csharp/components/type-expression.tsx +10 -3
  52. package/src/csharp/components/utils/doc-comments.tsx +58 -0
  53. package/src/typescript/components/arrow-function.tsx +1 -1
  54. package/src/typescript/components/function-expression.tsx +1 -1
  55. package/src/typescript/components/function-type.tsx +1 -1
  56. package/test/csharp/components/enum-declaration.test.tsx +50 -9
  57. package/test/test-host.ts +4 -0
  58. package/test/vitest.setup.ts +1 -0
  59. package/tsconfig.json +2 -1
  60. package/vitest.config.ts +2 -1
  61. package/dist/src/csharp/components/class-declaration.d.ts +0 -9
  62. package/dist/src/csharp/components/class-declaration.d.ts.map +0 -1
  63. package/dist/test/csharp/components/class-declaration.test.d.ts +0 -2
  64. package/dist/test/csharp/components/class-declaration.test.d.ts.map +0 -1
  65. package/dist/test/csharp/components/class-declaration.test.js +0 -421
  66. package/src/csharp/components/class-declaration.tsx +0 -87
  67. package/test/csharp/components/class-declaration.test.tsx +0 -344
@@ -0,0 +1,5 @@
1
+ import { resolvePath } from "@typespec/compiler";
2
+ import { createTester } from "@typespec/compiler/testing";
3
+ export const Tester = createTester(resolvePath(import.meta.dirname, ".."), {
4
+ libraries: []
5
+ });
@@ -0,0 +1,2 @@
1
+ import "@alloy-js/core/testing";
2
+ //# sourceMappingURL=vitest.setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest.setup.d.ts","sourceRoot":"","sources":["../../test/vitest.setup.ts"],"names":[],"mappings":"AAAA,OAAO,wBAAwB,CAAC"}
@@ -0,0 +1 @@
1
+ import "@alloy-js/core/testing";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/emitter-framework",
3
- "version": "0.9.0-dev.3",
3
+ "version": "0.9.0-dev.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -21,23 +21,26 @@
21
21
  "import": "./dist/src/testing/index.js"
22
22
  }
23
23
  },
24
+ "imports": {
25
+ "#test/*": "./test/*"
26
+ },
24
27
  "keywords": [],
25
28
  "author": "",
26
29
  "license": "MIT",
27
30
  "description": "",
28
31
  "peerDependencies": {
29
- "@alloy-js/core": "^0.17.0",
30
- "@alloy-js/typescript": "^0.17.0",
31
- "@alloy-js/csharp": "^0.17.0",
32
+ "@alloy-js/core": "^0.18.0",
33
+ "@alloy-js/typescript": "^0.18.0",
34
+ "@alloy-js/csharp": "^0.18.0",
32
35
  "@typespec/compiler": "^1.1.0",
33
36
  "@typespec/http": "^1.1.0",
34
37
  "@typespec/rest": "^0.71.0 || >=0.72.0-dev <0.72.0"
35
38
  },
36
39
  "devDependencies": {
37
- "@alloy-js/cli": "^0.17.0",
40
+ "@alloy-js/cli": "^0.18.0",
38
41
  "@alloy-js/rollup-plugin": "^0.1.0",
39
- "@alloy-js/core": "^0.17.0",
40
- "@alloy-js/typescript": "^0.17.0",
42
+ "@alloy-js/core": "^0.18.0",
43
+ "@alloy-js/typescript": "^0.18.0",
41
44
  "@types/minimist": "^1.2.5",
42
45
  "@typespec/compiler": "^1.1.0",
43
46
  "@typespec/http": "^1.1.0",
@@ -0,0 +1,401 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { Children, render } from "@alloy-js/core";
3
+ import { d } from "@alloy-js/core/testing";
4
+ import { createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
5
+ import { t, TesterInstance } from "@typespec/compiler/testing";
6
+ import { beforeEach, describe, it } from "vitest";
7
+ import { assertFileContents } from "../../../../test/csharp/utils.js";
8
+ import { Output } from "../../../core/index.js";
9
+ import { ClassDeclaration, EnumDeclaration } from "../../index.js";
10
+
11
+ let runner: TesterInstance;
12
+
13
+ beforeEach(async () => {
14
+ runner = await Tester.createInstance();
15
+ });
16
+
17
+ function Wrapper(props: { children: Children }) {
18
+ const policy = createCSharpNamePolicy();
19
+ return (
20
+ <Output program={runner.program} namePolicy={policy}>
21
+ <Namespace name="TestNamespace">
22
+ <SourceFile path="test.cs">{props.children}</SourceFile>
23
+ </Namespace>
24
+ </Output>
25
+ );
26
+ }
27
+
28
+ it("renders an empty class declaration", async () => {
29
+ const { TestModel } = await runner.compile(t.code`
30
+ model ${t.model("TestModel")} {}
31
+ `);
32
+
33
+ const res = render(
34
+ <Wrapper>
35
+ <ClassDeclaration type={TestModel} />
36
+ </Wrapper>,
37
+ );
38
+
39
+ assertFileContents(
40
+ res,
41
+ d`
42
+ namespace TestNamespace
43
+ {
44
+ class TestModel
45
+ {
46
+
47
+ }
48
+ }
49
+ `,
50
+ );
51
+ });
52
+
53
+ it("renders a class declaration with properties", async () => {
54
+ const { TestModel } = await runner.compile(t.code`
55
+ model ${t.model("TestModel")} {
56
+ @test Prop1: string;
57
+ @test Prop2: int32;
58
+ }
59
+ `);
60
+
61
+ const res = render(
62
+ <Wrapper>
63
+ <ClassDeclaration type={TestModel} />
64
+ </Wrapper>,
65
+ );
66
+
67
+ assertFileContents(
68
+ res,
69
+ d`
70
+ namespace TestNamespace
71
+ {
72
+ class TestModel
73
+ {
74
+ public required string Prop1 { get; set; }
75
+ public required int Prop2 { get; set; }
76
+ }
77
+ }
78
+ `,
79
+ );
80
+ });
81
+
82
+ it("can override class name", async () => {
83
+ const { TestModel } = await runner.compile(t.code`
84
+ model ${t.model("TestModel")} {}
85
+ `);
86
+
87
+ const res = render(
88
+ <Wrapper>
89
+ <ClassDeclaration type={TestModel} name="CustomClassName" />
90
+ </Wrapper>,
91
+ );
92
+
93
+ assertFileContents(
94
+ res,
95
+ d`
96
+ namespace TestNamespace
97
+ {
98
+ class CustomClassName
99
+ {
100
+
101
+ }
102
+ }
103
+ `,
104
+ );
105
+ });
106
+
107
+ it("renders a class with access modifiers", async () => {
108
+ const { TestModel } = await runner.compile(t.code`
109
+ model ${t.model("TestModel")} {
110
+ }
111
+ `);
112
+
113
+ const res = render(
114
+ <Wrapper>
115
+ <ClassDeclaration type={TestModel} protected />
116
+ </Wrapper>,
117
+ );
118
+
119
+ assertFileContents(
120
+ res,
121
+ d`
122
+ namespace TestNamespace
123
+ {
124
+ protected class TestModel
125
+ {
126
+
127
+ }
128
+ }
129
+ `,
130
+ );
131
+ });
132
+
133
+ describe("from an interface", () => {
134
+ it("renders an empty class", async () => {
135
+ const { TestInterface } = await runner.compile(t.code`
136
+ interface ${t.interface("TestInterface")} {
137
+ }
138
+ `);
139
+
140
+ const res = render(
141
+ <Wrapper>
142
+ <ClassDeclaration type={TestInterface} />
143
+ </Wrapper>,
144
+ );
145
+
146
+ assertFileContents(
147
+ res,
148
+ d`
149
+ namespace TestNamespace
150
+ {
151
+ class TestInterface
152
+ {
153
+
154
+ }
155
+ }
156
+ `,
157
+ );
158
+ });
159
+
160
+ it("renders a class with operations", async () => {
161
+ const { TestInterface } = await runner.compile(t.code`
162
+ interface ${t.interface("TestInterface")} {
163
+ op getName(id: string): string;
164
+ }
165
+ `);
166
+
167
+ const res = render(
168
+ <Wrapper>
169
+ <ClassDeclaration type={TestInterface} />
170
+ </Wrapper>,
171
+ );
172
+
173
+ assertFileContents(
174
+ res,
175
+ d`
176
+ namespace TestNamespace
177
+ {
178
+ class TestInterface
179
+ {
180
+ public abstract string GetName(string id);
181
+ }
182
+ }
183
+ `,
184
+ );
185
+ });
186
+ });
187
+
188
+ it("renders a class with model members", async () => {
189
+ const { TestModel, TestReference } = await runner.compile(t.code`
190
+ model ${t.model("TestReference")} { }
191
+ model ${t.model("TestModel")} {
192
+ prop1: TestReference;
193
+ }
194
+ `);
195
+
196
+ const res = render(
197
+ <Wrapper>
198
+ <ClassDeclaration type={TestReference} />
199
+ <hbr />
200
+ <ClassDeclaration type={TestModel} />
201
+ </Wrapper>,
202
+ );
203
+
204
+ assertFileContents(
205
+ res,
206
+ d`
207
+ namespace TestNamespace
208
+ {
209
+ class TestReference
210
+ {
211
+
212
+ }
213
+ class TestModel
214
+ {
215
+ public required TestReference Prop1 { get; set; }
216
+ }
217
+ }
218
+ `,
219
+ );
220
+ });
221
+
222
+ it("renders a class with enum members", async () => {
223
+ const { TestModel, TestEnum } = await runner.compile(t.code`
224
+ @test enum ${t.enum("TestEnum")} {
225
+ Value1;
226
+ Value2;
227
+ }
228
+ model ${t.model("TestModel")} {
229
+ @test prop1: TestEnum;
230
+ }
231
+ `);
232
+
233
+ const res = render(
234
+ <Wrapper>
235
+ <EnumDeclaration type={TestEnum} />
236
+ <hbr />
237
+ <ClassDeclaration type={TestModel} />
238
+ </Wrapper>,
239
+ );
240
+
241
+ assertFileContents(
242
+ res,
243
+ d`
244
+ namespace TestNamespace
245
+ {
246
+ enum TestEnum
247
+ {
248
+ Value1,
249
+ Value2
250
+ }
251
+ class TestModel
252
+ {
253
+ public required TestEnum Prop1 { get; set; }
254
+ }
255
+ }
256
+ `,
257
+ );
258
+ });
259
+
260
+ it("maps prop: string | null to nullable property", async () => {
261
+ const { TestModel } = await runner.compile(t.code`
262
+ model ${t.model("TestModel")} {
263
+ prop1: string | null;
264
+ }
265
+ `);
266
+
267
+ const res = render(
268
+ <Wrapper>
269
+ <ClassDeclaration type={TestModel} />
270
+ </Wrapper>,
271
+ );
272
+
273
+ assertFileContents(
274
+ res,
275
+ d`
276
+ namespace TestNamespace
277
+ {
278
+ class TestModel
279
+ {
280
+ public required string? Prop1 { get; set; }
281
+ }
282
+ }
283
+ `,
284
+ );
285
+ });
286
+
287
+ it("renders a class with string enums", async () => {
288
+ const { TestModel, TestEnum } = await runner.compile(t.code`
289
+ @test enum ${t.enum("TestEnum")} {
290
+ Value1;
291
+ Value2;
292
+ }
293
+ model ${t.model("TestModel")} {
294
+ @test prop1: TestEnum;
295
+ }
296
+ `);
297
+
298
+ const res = render(
299
+ <Wrapper>
300
+ <EnumDeclaration type={TestEnum} />
301
+ <hbr />
302
+ <ClassDeclaration type={TestModel} />
303
+ </Wrapper>,
304
+ );
305
+
306
+ assertFileContents(
307
+ res,
308
+ d`
309
+ namespace TestNamespace
310
+ {
311
+ enum TestEnum
312
+ {
313
+ Value1,
314
+ Value2
315
+ }
316
+ class TestModel
317
+ {
318
+ public required TestEnum Prop1 { get; set; }
319
+ }
320
+ }
321
+ `,
322
+ );
323
+ });
324
+
325
+ describe("with doc comments", () => {
326
+ it("renders a model with docs", async () => {
327
+ const { TestModel } = await runner.compile(t.code`
328
+ @doc("This is a test model")
329
+ model ${t.model("TestModel")} {
330
+ @doc("This is a test property")
331
+ prop1: string;
332
+ }
333
+
334
+ `);
335
+
336
+ const res = render(
337
+ <Wrapper>
338
+ <ClassDeclaration type={TestModel} />
339
+ </Wrapper>,
340
+ );
341
+
342
+ assertFileContents(
343
+ res,
344
+ d`
345
+ namespace TestNamespace
346
+ {
347
+ /// <summary>
348
+ /// This is a test model
349
+ /// </summary>
350
+ class TestModel
351
+ {
352
+ /// <summary>
353
+ /// This is a test property
354
+ /// </summary>
355
+ public required string Prop1 { get; set; }
356
+ }
357
+ }
358
+ `,
359
+ );
360
+ });
361
+
362
+ it("renders an interface with docs", async () => {
363
+ const { TestInterface } = await runner.compile(t.code`
364
+ @doc("This is a test interface")
365
+ @test interface ${t.interface("TestInterface")} {
366
+ @doc("This is a test operation")
367
+ @returnsDoc("The name of the item")
368
+ op getName(id: string): string;
369
+ }
370
+ `);
371
+
372
+ const res = render(
373
+ <Wrapper>
374
+ <ClassDeclaration type={TestInterface} />
375
+ </Wrapper>,
376
+ );
377
+
378
+ assertFileContents(
379
+ res,
380
+ d`
381
+ namespace TestNamespace
382
+ {
383
+ /// <summary>
384
+ /// This is a test interface
385
+ /// </summary>
386
+ class TestInterface
387
+ {
388
+ /// <summary>
389
+ /// This is a test operation
390
+ /// </summary>
391
+ ///
392
+ /// <returns>
393
+ /// The name of the item
394
+ /// </returns>
395
+ public abstract string GetName(string id);
396
+ }
397
+ }
398
+ `,
399
+ );
400
+ });
401
+ });
@@ -0,0 +1,86 @@
1
+ import * as ay from "@alloy-js/core";
2
+ import * as cs from "@alloy-js/csharp";
3
+ import { 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): ay.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): ay.Children {
55
+ return (
56
+ <ay.For each={props.type.properties.entries()} hardline>
57
+ {([name, property]) => <Property type={property} jsonAttributes={props.jsonAttributes} />}
58
+ </ay.For>
59
+ );
60
+ }
61
+
62
+ function ClassMethods(props: ClassMethodsProps): ay.Children {
63
+ const { $ } = useTsp();
64
+ const namePolicy = cs.useCSharpNamePolicy();
65
+
66
+ const abstractMethods: ay.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
+ }
@@ -3,9 +3,10 @@ import * as cs from "@alloy-js/csharp";
3
3
  import { Enum, Union } from "@typespec/compiler";
4
4
  import { useTsp } from "../../core/index.js";
5
5
  import { reportDiagnostic } from "../../lib.js";
6
+ import { getDocComments } from "./utils/doc-comments.jsx";
6
7
  import { declarationRefkeys, efRefkey } from "./utils/refkey.js";
7
8
 
8
- export interface EnumDeclarationProps extends Omit<cs.EnumProps, "name"> {
9
+ export interface EnumDeclarationProps extends Omit<cs.EnumDeclarationProps, "name"> {
9
10
  name?: string;
10
11
  type: Union | Enum;
11
12
  }
@@ -30,19 +31,26 @@ export function EnumDeclaration(props: EnumDeclarationProps): ay.Children {
30
31
  const members = Array.from(type.members.entries());
31
32
 
32
33
  return (
33
- <cs.Enum name={name} refkey={refkeys} accessModifier={props.accessModifier ?? "public"}>
34
- <ay.For each={members} joiner={",\n"}>
35
- {([key, value]) => {
36
- return (
37
- <cs.EnumMember
38
- name={cs.useCSharpNamePolicy().getName(key, "enum-member")}
39
- refkey={
40
- $.union.is(props.type) ? efRefkey(props.type.variants.get(key)) : efRefkey(value)
41
- }
42
- />
43
- );
44
- }}
45
- </ay.For>
46
- </cs.Enum>
34
+ <>
35
+ <cs.EnumDeclaration name={name} refkey={refkeys} {...props}>
36
+ <ay.For each={members} joiner={",\n"}>
37
+ {([key, value]) => {
38
+ return (
39
+ <>
40
+ <cs.DocWhen doc={getDocComments($, value)} />
41
+ <cs.EnumMember
42
+ name={cs.useCSharpNamePolicy().getName(key, "enum-member")}
43
+ refkey={
44
+ $.union.is(props.type)
45
+ ? efRefkey(props.type.variants.get(key))
46
+ : efRefkey(value)
47
+ }
48
+ />
49
+ </>
50
+ );
51
+ }}
52
+ </ay.For>
53
+ </cs.EnumDeclaration>
54
+ </>
47
55
  );
48
56
  }
@@ -1,3 +1,4 @@
1
- export * from "./class-declaration.jsx";
1
+ export * from "./class/declaration.js";
2
2
  export * from "./enum-declaration.jsx";
3
+ export * from "./property/property.jsx";
3
4
  export * from "./type-expression.jsx";
@@ -0,0 +1,97 @@
1
+ import { Tester } from "#test/test-host.js";
2
+ import { Children } from "@alloy-js/core";
3
+ import { ClassDeclaration, createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
4
+ import { t, TesterInstance } from "@typespec/compiler/testing";
5
+ import { beforeEach, describe, expect, it } from "vitest";
6
+ import { Output } from "../../../core/components/output.jsx";
7
+ import { Property } from "./property.jsx";
8
+
9
+ let tester: TesterInstance;
10
+
11
+ beforeEach(async () => {
12
+ tester = await Tester.createInstance();
13
+ });
14
+
15
+ function Wrapper(props: { children: Children }) {
16
+ const policy = createCSharpNamePolicy();
17
+ return (
18
+ <Output program={tester.program} namePolicy={policy}>
19
+ <Namespace name="TestNamespace">
20
+ <SourceFile path="test.cs">
21
+ <ClassDeclaration name="Test">{props.children}</ClassDeclaration>
22
+ </SourceFile>
23
+ </Namespace>
24
+ </Output>
25
+ );
26
+ }
27
+
28
+ it("maps prop: string | null to nullable property", async () => {
29
+ const { prop1 } = await tester.compile(t.code`
30
+ model TestModel {
31
+ ${t.modelProperty("prop1")}: string | null;
32
+ }
33
+ `);
34
+
35
+ expect(
36
+ <Wrapper>
37
+ <Property type={prop1} />
38
+ </Wrapper>,
39
+ ).toRenderTo(`
40
+ namespace TestNamespace
41
+ {
42
+ class Test
43
+ {
44
+ public required string? Prop1 { get; set; }
45
+ }
46
+ }
47
+ `);
48
+ });
49
+
50
+ describe("jsonAttributes", () => {
51
+ it("adds [JsonNameAttribute]", async () => {
52
+ const { prop1 } = await tester.compile(t.code`
53
+ model TestModel {
54
+ ${t.modelProperty("prop1")}: string;
55
+ }
56
+ `);
57
+
58
+ expect(
59
+ <Wrapper>
60
+ <Property type={prop1} jsonAttributes />
61
+ </Wrapper>,
62
+ ).toRenderTo(`
63
+ namespace TestNamespace
64
+ {
65
+ class Test
66
+ {
67
+ [System.Text.Json.JsonPropertyName("prop1")]
68
+ public required string Prop1 { get; set; }
69
+ }
70
+ }
71
+ `);
72
+ });
73
+
74
+ it("adds [JsonNameAttribute] respecting encodedName", async () => {
75
+ const { prop1 } = await tester.compile(t.code`
76
+ model TestModel {
77
+ @encodedName("application/json", "prop_1")
78
+ ${t.modelProperty("prop1")}: string;
79
+ }
80
+ `);
81
+
82
+ expect(
83
+ <Wrapper>
84
+ <Property type={prop1} jsonAttributes />
85
+ </Wrapper>,
86
+ ).toRenderTo(`
87
+ namespace TestNamespace
88
+ {
89
+ class Test
90
+ {
91
+ [System.Text.Json.JsonPropertyName("prop_1")]
92
+ public required string Prop1 { get; set; }
93
+ }
94
+ }
95
+ `);
96
+ });
97
+ });