@typespec/emitter-framework 0.11.0-dev.0 → 0.11.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.
- package/dist/src/core/components/index.d.ts +2 -0
- package/dist/src/core/components/index.d.ts.map +1 -1
- package/dist/src/core/components/index.js +4 -1
- package/dist/src/core/components/index.js.map +1 -0
- package/dist/src/core/components/output.js +2 -1
- package/dist/src/core/components/output.js.map +1 -0
- package/dist/src/core/components/overrides/component-overrides.d.ts +64 -0
- package/dist/src/core/components/overrides/component-overrides.d.ts.map +1 -0
- package/dist/src/core/components/overrides/component-overrides.js +41 -0
- package/dist/src/core/components/overrides/component-overrides.js.map +1 -0
- package/dist/src/core/components/overrides/config.d.ts +28 -0
- package/dist/src/core/components/overrides/config.d.ts.map +1 -0
- package/dist/src/core/components/overrides/config.js +55 -0
- package/dist/src/core/components/overrides/config.js.map +1 -0
- package/dist/src/core/components/overrides/context.d.ts +11 -0
- package/dist/src/core/components/overrides/context.d.ts.map +1 -0
- package/dist/src/core/components/overrides/context.js +9 -0
- package/dist/src/core/components/overrides/context.js.map +1 -0
- package/dist/src/core/context/index.js +2 -1
- package/dist/src/core/context/index.js.map +1 -0
- package/dist/src/core/context/name-policy-context.js +2 -1
- package/dist/src/core/context/name-policy-context.js.map +1 -0
- package/dist/src/core/context/tsp-context.js +2 -1
- package/dist/src/core/context/tsp-context.js.map +1 -0
- package/dist/src/core/index.js +2 -1
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/transport-name-policy.js +2 -1
- package/dist/src/core/transport-name-policy.js.map +1 -0
- package/dist/src/core/write-output.d.ts.map +1 -1
- package/dist/src/core/write-output.js +4 -3
- package/dist/src/core/write-output.js.map +1 -0
- package/dist/src/csharp/components/class/declaration.d.ts +1 -1
- package/dist/src/csharp/components/class/declaration.d.ts.map +1 -1
- package/dist/src/csharp/components/class/declaration.js +14 -5
- package/dist/src/csharp/components/class/declaration.js.map +1 -0
- package/dist/src/csharp/components/class/declaration.test.js +125 -92
- package/dist/src/csharp/components/class/declaration.test.js.map +1 -0
- package/dist/src/csharp/components/enum/declaration.js +2 -1
- package/dist/src/csharp/components/enum/declaration.js.map +1 -0
- package/dist/src/csharp/components/enum/declaration.test.js +52 -88
- package/dist/src/csharp/components/enum/declaration.test.js.map +1 -0
- package/dist/src/csharp/components/index.js +2 -1
- package/dist/src/csharp/components/index.js.map +1 -0
- package/dist/src/csharp/components/property/property.d.ts.map +1 -1
- package/dist/src/csharp/components/property/property.js +40 -14
- package/dist/src/csharp/components/property/property.js.map +1 -0
- package/dist/src/csharp/components/property/property.test.js +129 -29
- package/dist/src/csharp/components/property/property.test.js.map +1 -0
- package/dist/src/csharp/components/type-expression.d.ts.map +1 -1
- package/dist/src/csharp/components/type-expression.js +34 -6
- package/dist/src/csharp/components/type-expression.js.map +1 -0
- package/dist/src/csharp/components/type-expression.test.js +87 -54
- package/dist/src/csharp/components/type-expression.test.js.map +1 -0
- package/dist/src/csharp/components/utils/doc-comments.js +2 -1
- package/dist/src/csharp/components/utils/doc-comments.js.map +1 -0
- package/dist/src/csharp/components/utils/nullable-util.d.ts +4 -0
- package/dist/src/csharp/components/utils/nullable-util.d.ts.map +1 -0
- package/dist/src/csharp/components/utils/nullable-util.js +27 -0
- package/dist/src/csharp/components/utils/nullable-util.js.map +1 -0
- package/dist/src/csharp/components/utils/refkey.js +2 -1
- package/dist/src/csharp/components/utils/refkey.js.map +1 -0
- package/dist/src/csharp/index.js +2 -1
- package/dist/src/csharp/index.js.map +1 -0
- package/dist/src/lib.js +2 -1
- package/dist/src/lib.js.map +1 -0
- package/dist/src/testing/index.js +2 -1
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/scenario-test/code-block-expectation.js +2 -1
- package/dist/src/testing/scenario-test/code-block-expectation.js.map +1 -0
- package/dist/src/testing/scenario-test/code-block-expectation.test.js +2 -1
- package/dist/src/testing/scenario-test/code-block-expectation.test.js.map +1 -0
- package/dist/src/testing/scenario-test/harness.js +8 -2
- package/dist/src/testing/scenario-test/harness.js.map +1 -0
- package/dist/src/testing/scenario-test/index.js +2 -1
- package/dist/src/testing/scenario-test/index.js.map +1 -0
- package/dist/src/testing/scenario-test/snippet-extractor.js +2 -1
- package/dist/src/testing/scenario-test/snippet-extractor.js.map +1 -0
- package/dist/src/typescript/components/array-expression.js +2 -1
- package/dist/src/typescript/components/array-expression.js.map +1 -0
- package/dist/src/typescript/components/arrow-function.js +2 -1
- package/dist/src/typescript/components/arrow-function.js.map +1 -0
- package/dist/src/typescript/components/class-method.js +2 -1
- package/dist/src/typescript/components/class-method.js.map +1 -0
- package/dist/src/typescript/components/enum-declaration.js +2 -1
- package/dist/src/typescript/components/enum-declaration.js.map +1 -0
- package/dist/src/typescript/components/function-declaration.js +2 -1
- package/dist/src/typescript/components/function-declaration.js.map +1 -0
- package/dist/src/typescript/components/function-expression.js +2 -1
- package/dist/src/typescript/components/function-expression.js.map +1 -0
- package/dist/src/typescript/components/function-type.js +2 -1
- package/dist/src/typescript/components/function-type.js.map +1 -0
- package/dist/src/typescript/components/index.js +2 -1
- package/dist/src/typescript/components/index.js.map +1 -0
- package/dist/src/typescript/components/interface-declaration.js +2 -1
- package/dist/src/typescript/components/interface-declaration.js.map +1 -0
- package/dist/src/typescript/components/interface-member.d.ts.map +1 -1
- package/dist/src/typescript/components/interface-member.js +13 -20
- package/dist/src/typescript/components/interface-member.js.map +1 -0
- package/dist/src/typescript/components/interface-method.js +2 -1
- package/dist/src/typescript/components/interface-method.js.map +1 -0
- package/dist/src/typescript/components/record-expression.js +2 -1
- package/dist/src/typescript/components/record-expression.js.map +1 -0
- package/dist/src/typescript/components/static-serializers.js +2 -1
- package/dist/src/typescript/components/static-serializers.js.map +1 -0
- package/dist/src/typescript/components/type-alias-declaration.js +2 -1
- package/dist/src/typescript/components/type-alias-declaration.js.map +1 -0
- package/dist/src/typescript/components/type-declaration.js +2 -1
- package/dist/src/typescript/components/type-declaration.js.map +1 -0
- package/dist/src/typescript/components/type-expression.d.ts +0 -1
- package/dist/src/typescript/components/type-expression.d.ts.map +1 -1
- package/dist/src/typescript/components/type-expression.js +13 -12
- package/dist/src/typescript/components/type-expression.js.map +1 -0
- package/dist/src/typescript/components/type-transform.d.ts.map +1 -1
- package/dist/src/typescript/components/type-transform.js +5 -4
- package/dist/src/typescript/components/type-transform.js.map +1 -0
- package/dist/src/typescript/components/union/declaration.js +2 -1
- package/dist/src/typescript/components/union/declaration.js.map +1 -0
- package/dist/src/typescript/components/union/declaration.test.js +2 -1
- package/dist/src/typescript/components/union/declaration.test.js.map +1 -0
- package/dist/src/typescript/components/union/expression.js +2 -1
- package/dist/src/typescript/components/union/expression.js.map +1 -0
- package/dist/src/typescript/components/union/expression.test.js +2 -1
- package/dist/src/typescript/components/union/expression.test.js.map +1 -0
- package/dist/src/typescript/components/value-expression.js +2 -1
- package/dist/src/typescript/components/value-expression.js.map +1 -0
- package/dist/src/typescript/index.js +2 -1
- package/dist/src/typescript/index.js.map +1 -0
- package/dist/src/typescript/lib.js +2 -1
- package/dist/src/typescript/lib.js.map +1 -0
- package/dist/src/typescript/utils/index.js +2 -1
- package/dist/src/typescript/utils/index.js.map +1 -0
- package/dist/src/typescript/utils/operation.js +2 -1
- package/dist/src/typescript/utils/operation.js.map +1 -0
- package/dist/src/typescript/utils/refkey.js +2 -1
- package/dist/src/typescript/utils/refkey.js.map +1 -0
- package/dist/test/test-host.js +2 -1
- package/dist/test/test-host.js.map +1 -0
- package/dist/test/testing/snippet-extractor-csharp.test.js +2 -1
- package/dist/test/testing/snippet-extractor-csharp.test.js.map +1 -0
- package/dist/test/testing/snippet-extractor-java.test.js +2 -1
- package/dist/test/testing/snippet-extractor-java.test.js.map +1 -0
- package/dist/test/testing/snippet-extractor-python.test.js +2 -1
- package/dist/test/testing/snippet-extractor-python.test.js.map +1 -0
- package/dist/test/testing/snippet-extractor-typescript.test.js +2 -1
- package/dist/test/testing/snippet-extractor-typescript.test.js.map +1 -0
- package/dist/test/typescript/components/arrow-function.test.js +18 -22
- package/dist/test/typescript/components/arrow-function.test.js.map +1 -0
- package/dist/test/typescript/components/component-override.test.d.ts +2 -0
- package/dist/test/typescript/components/component-override.test.d.ts.map +1 -0
- package/dist/test/typescript/components/component-override.test.js +78 -0
- package/dist/test/typescript/components/component-override.test.js.map +1 -0
- package/dist/test/typescript/components/enum-declaration.test.js +2 -1
- package/dist/test/typescript/components/enum-declaration.test.js.map +1 -0
- package/dist/test/typescript/components/function-declaration.test.js +3 -2
- package/dist/test/typescript/components/function-declaration.test.js.map +1 -0
- package/dist/test/typescript/components/function-expression.test.js +18 -22
- package/dist/test/typescript/components/function-expression.test.js.map +1 -0
- package/dist/test/typescript/components/function-type.test.js +18 -22
- package/dist/test/typescript/components/function-type.test.js.map +1 -0
- package/dist/test/typescript/components/interface-declaration.test.js +3 -2
- package/dist/test/typescript/components/interface-declaration.test.js.map +1 -0
- package/dist/test/typescript/components/interface-method.test.js +37 -45
- package/dist/test/typescript/components/interface-method.test.js.map +1 -0
- package/dist/test/typescript/components/member-expression.test.js +2 -1
- package/dist/test/typescript/components/member-expression.test.js.map +1 -0
- package/dist/test/typescript/components/type-alias-declaration.test.js +8 -5
- package/dist/test/typescript/components/type-alias-declaration.test.js.map +1 -0
- package/dist/test/typescript/components/type-transform.test.js +29 -27
- package/dist/test/typescript/components/type-transform.test.js.map +1 -0
- package/dist/test/typescript/components/value-expression.test.js +3 -2
- package/dist/test/typescript/components/value-expression.test.js.map +1 -0
- package/dist/test/typescript/utils.js +2 -1
- package/dist/test/typescript/utils.js.map +1 -0
- package/dist/test/utils.d.ts +1 -0
- package/dist/test/utils.d.ts.map +1 -1
- package/dist/test/utils.js +13 -3
- package/dist/test/utils.js.map +1 -0
- package/dist/test/vitest.setup.js +2 -1
- package/dist/test/vitest.setup.js.map +1 -0
- package/package.json +9 -13
- package/src/core/components/index.tsx +2 -0
- package/src/core/components/overrides/component-overrides.tsx +134 -0
- package/src/core/components/overrides/config.ts +85 -0
- package/src/core/components/overrides/context.ts +14 -0
- package/src/core/write-output.ts +2 -2
- package/src/csharp/components/class/declaration.test.tsx +114 -88
- package/src/csharp/components/class/declaration.tsx +13 -3
- package/src/csharp/components/enum/declaration.test.tsx +47 -78
- package/src/csharp/components/property/property.test.tsx +108 -25
- package/src/csharp/components/property/property.tsx +43 -11
- package/src/csharp/components/type-expression.test.tsx +84 -69
- package/src/csharp/components/type-expression.tsx +31 -5
- package/src/csharp/components/utils/nullable-util.ts +25 -0
- package/src/testing/scenario-test/harness.ts +6 -1
- package/src/typescript/components/interface-member.tsx +8 -14
- package/src/typescript/components/type-expression.tsx +7 -8
- package/src/typescript/components/type-transform.tsx +3 -7
- package/test/typescript/components/arrow-function.test.tsx +23 -42
- package/test/typescript/components/component-override.test.tsx +71 -0
- package/test/typescript/components/function-declaration.test.tsx +2 -1
- package/test/typescript/components/function-expression.test.tsx +23 -42
- package/test/typescript/components/function-type.test.tsx +22 -40
- package/test/typescript/components/interface-declaration.test.tsx +1 -1
- package/test/typescript/components/interface-method.test.tsx +50 -92
- package/test/typescript/components/type-alias-declaration.test.tsx +8 -6
- package/test/typescript/components/type-transform.test.tsx +37 -37
- package/test/typescript/components/value-expression.test.tsx +1 -1
- package/test/utils.ts +10 -3
- package/dist/test/typescript/test-host.d.ts +0 -16
- package/dist/test/typescript/test-host.d.ts.map +0 -1
- package/dist/test/typescript/test-host.js +0 -40
- package/test/typescript/test-host.ts +0 -49
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Tester } from "#test/test-host.js";
|
|
2
|
-
import { type Children } from "@alloy-js/core";
|
|
3
|
-
import { ClassDeclaration, createCSharpNamePolicy,
|
|
2
|
+
import { List, type Children } from "@alloy-js/core";
|
|
3
|
+
import { ClassDeclaration, createCSharpNamePolicy, SourceFile } from "@alloy-js/csharp";
|
|
4
4
|
import { t, type TesterInstance } from "@typespec/compiler/testing";
|
|
5
5
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
6
6
|
import { Output } from "../../../core/components/output.jsx";
|
|
@@ -16,11 +16,9 @@ function Wrapper(props: { children: Children }) {
|
|
|
16
16
|
const policy = createCSharpNamePolicy();
|
|
17
17
|
return (
|
|
18
18
|
<Output program={tester.program} namePolicy={policy}>
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
</SourceFile>
|
|
23
|
-
</Namespace>
|
|
19
|
+
<SourceFile path="test.cs">
|
|
20
|
+
<ClassDeclaration name="Test">{props.children}</ClassDeclaration>
|
|
21
|
+
</SourceFile>
|
|
24
22
|
</Output>
|
|
25
23
|
);
|
|
26
24
|
}
|
|
@@ -37,12 +35,47 @@ it("maps prop: string | null to nullable property", async () => {
|
|
|
37
35
|
<Property type={prop1} />
|
|
38
36
|
</Wrapper>,
|
|
39
37
|
).toRenderTo(`
|
|
40
|
-
|
|
38
|
+
class Test
|
|
41
39
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
public required string? Prop1 { get; set; }
|
|
41
|
+
}
|
|
42
|
+
`);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("maps optional properties to nullable properties", async () => {
|
|
46
|
+
const { prop1 } = await tester.compile(t.code`
|
|
47
|
+
model TestModel {
|
|
48
|
+
${t.modelProperty("prop1")}?: string;
|
|
49
|
+
}
|
|
50
|
+
`);
|
|
51
|
+
|
|
52
|
+
expect(
|
|
53
|
+
<Wrapper>
|
|
54
|
+
<Property type={prop1} />
|
|
55
|
+
</Wrapper>,
|
|
56
|
+
).toRenderTo(`
|
|
57
|
+
class Test
|
|
58
|
+
{
|
|
59
|
+
public string? Prop1 { get; set; }
|
|
60
|
+
}
|
|
61
|
+
`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("maps optional and nullable properties to nullable properties", async () => {
|
|
65
|
+
const { prop1 } = await tester.compile(t.code`
|
|
66
|
+
model TestModel {
|
|
67
|
+
${t.modelProperty("prop1")}?: string | null;
|
|
68
|
+
}
|
|
69
|
+
`);
|
|
70
|
+
|
|
71
|
+
expect(
|
|
72
|
+
<Wrapper>
|
|
73
|
+
<Property type={prop1} />
|
|
74
|
+
</Wrapper>,
|
|
75
|
+
).toRenderTo(`
|
|
76
|
+
class Test
|
|
77
|
+
{
|
|
78
|
+
public string? Prop1 { get; set; }
|
|
46
79
|
}
|
|
47
80
|
`);
|
|
48
81
|
});
|
|
@@ -60,13 +93,10 @@ describe("jsonAttributes", () => {
|
|
|
60
93
|
<Property type={prop1} jsonAttributes />
|
|
61
94
|
</Wrapper>,
|
|
62
95
|
).toRenderTo(`
|
|
63
|
-
|
|
96
|
+
class Test
|
|
64
97
|
{
|
|
65
|
-
|
|
66
|
-
{
|
|
67
|
-
[System.Text.Json.JsonPropertyName("prop1")]
|
|
68
|
-
public required string Prop1 { get; set; }
|
|
69
|
-
}
|
|
98
|
+
[System.Text.Json.JsonPropertyName("prop1")]
|
|
99
|
+
public required string Prop1 { get; set; }
|
|
70
100
|
}
|
|
71
101
|
`);
|
|
72
102
|
});
|
|
@@ -84,14 +114,67 @@ describe("jsonAttributes", () => {
|
|
|
84
114
|
<Property type={prop1} jsonAttributes />
|
|
85
115
|
</Wrapper>,
|
|
86
116
|
).toRenderTo(`
|
|
87
|
-
|
|
117
|
+
class Test
|
|
118
|
+
{
|
|
119
|
+
[System.Text.Json.JsonPropertyName("prop_1")]
|
|
120
|
+
public required string Prop1 { get; set; }
|
|
121
|
+
}
|
|
122
|
+
`);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("inherit prop: override, new", async () => {
|
|
126
|
+
const r = await tester.compile(t.code`
|
|
127
|
+
model TestModel extends BaseModel {
|
|
128
|
+
${t.modelProperty("prop1")}: string;
|
|
129
|
+
${t.modelProperty("prop2")}: string | null;
|
|
130
|
+
}
|
|
131
|
+
model BaseModel {
|
|
132
|
+
prop1: string | null;
|
|
133
|
+
prop2: string | null;
|
|
134
|
+
}
|
|
135
|
+
`);
|
|
136
|
+
|
|
137
|
+
expect(
|
|
138
|
+
<Wrapper>
|
|
139
|
+
<List>
|
|
140
|
+
<Property type={r.prop1} />
|
|
141
|
+
<Property type={r.prop2} />
|
|
142
|
+
</List>
|
|
143
|
+
</Wrapper>,
|
|
144
|
+
).toRenderTo(`
|
|
145
|
+
class Test
|
|
88
146
|
{
|
|
89
|
-
|
|
90
|
-
{
|
|
91
|
-
[System.Text.Json.JsonPropertyName("prop_1")]
|
|
92
|
-
public required string Prop1 { get; set; }
|
|
93
|
-
}
|
|
147
|
+
public new required string Prop1 { get; set; }
|
|
148
|
+
public override required string? Prop2 { get; set; }
|
|
94
149
|
}
|
|
95
|
-
|
|
150
|
+
`);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("inherit prop: virtual", async () => {
|
|
154
|
+
const r = await tester.compile(t.code`
|
|
155
|
+
model TestModel extends BaseModel {
|
|
156
|
+
prop1: string;
|
|
157
|
+
prop2: string | null;
|
|
158
|
+
}
|
|
159
|
+
model BaseModel {
|
|
160
|
+
${t.modelProperty("prop1")}: string | null;
|
|
161
|
+
${t.modelProperty("prop2")}: string | null;
|
|
162
|
+
}
|
|
163
|
+
`);
|
|
164
|
+
|
|
165
|
+
expect(
|
|
166
|
+
<Wrapper>
|
|
167
|
+
<List>
|
|
168
|
+
<Property type={r.prop1} />
|
|
169
|
+
<Property type={r.prop2} />
|
|
170
|
+
</List>
|
|
171
|
+
</Wrapper>,
|
|
172
|
+
).toRenderTo(`
|
|
173
|
+
class Test
|
|
174
|
+
{
|
|
175
|
+
public required string? Prop1 { get; set; }
|
|
176
|
+
public virtual required string? Prop2 { get; set; }
|
|
177
|
+
}
|
|
178
|
+
`);
|
|
96
179
|
});
|
|
97
180
|
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type Children } from "@alloy-js/core";
|
|
2
2
|
import * as cs from "@alloy-js/csharp";
|
|
3
3
|
import { Attribute } from "@alloy-js/csharp";
|
|
4
|
-
import { type ModelProperty, resolveEncodedName, type Type } from "@typespec/compiler";
|
|
4
|
+
import { getProperty, type ModelProperty, resolveEncodedName, type Type } from "@typespec/compiler";
|
|
5
5
|
import { useTsp } from "../../../core/index.js";
|
|
6
6
|
import { TypeExpression } from "../type-expression.jsx";
|
|
7
7
|
import { getDocComments } from "../utils/doc-comments.jsx";
|
|
8
|
+
import { getNullableUnionInnerType } from "../utils/nullable-util.js";
|
|
8
9
|
|
|
9
10
|
export interface PropertyProps {
|
|
10
11
|
type: ModelProperty;
|
|
@@ -16,14 +17,47 @@ export interface PropertyProps {
|
|
|
16
17
|
* Create a C# property declaration from a TypeSpec property type.
|
|
17
18
|
*/
|
|
18
19
|
export function Property(props: PropertyProps): Children {
|
|
19
|
-
const result = preprocessPropertyType(props.type
|
|
20
|
+
const result = preprocessPropertyType(props.type);
|
|
20
21
|
const { $ } = useTsp();
|
|
21
22
|
|
|
23
|
+
let overrideType: "" | "override" | "new" = "";
|
|
24
|
+
let isVirtual = false;
|
|
25
|
+
if (props.type.model) {
|
|
26
|
+
if (props.type.model.baseModel) {
|
|
27
|
+
const base = props.type.model.baseModel;
|
|
28
|
+
const baseProperty = getProperty(base, props.type.name);
|
|
29
|
+
if (baseProperty) {
|
|
30
|
+
const baseResult = preprocessPropertyType(baseProperty);
|
|
31
|
+
if (baseResult.nullable === result.nullable && baseResult.type === result.type) {
|
|
32
|
+
overrideType = "override";
|
|
33
|
+
} else {
|
|
34
|
+
overrideType = "new";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (
|
|
39
|
+
overrideType === "" &&
|
|
40
|
+
props.type.model.derivedModels &&
|
|
41
|
+
props.type.model.derivedModels.length > 0
|
|
42
|
+
) {
|
|
43
|
+
isVirtual = props.type.model.derivedModels.some((derived) => {
|
|
44
|
+
const derivedProperty = derived.properties.get(props.type.name);
|
|
45
|
+
if (derivedProperty) {
|
|
46
|
+
const derivedResult = preprocessPropertyType(derivedProperty);
|
|
47
|
+
return derivedResult.nullable === result.nullable && derivedResult.type === result.type;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
22
53
|
return (
|
|
23
54
|
<cs.Property
|
|
24
55
|
name={props.type.name}
|
|
25
56
|
type={<TypeExpression type={result.type} />}
|
|
57
|
+
override={overrideType === "override"}
|
|
58
|
+
new={overrideType === "new"}
|
|
26
59
|
public
|
|
60
|
+
virtual={isVirtual}
|
|
27
61
|
required={!props.type.optional}
|
|
28
62
|
nullable={result.nullable}
|
|
29
63
|
doc={getDocComments($, props.type)}
|
|
@@ -44,19 +78,17 @@ function JsonNameAttribute(props: JsonNameAttributeProps): Children {
|
|
|
44
78
|
return <Attribute name="System.Text.Json.JsonPropertyName" args={[JSON.stringify(jsonName)]} />;
|
|
45
79
|
}
|
|
46
80
|
|
|
47
|
-
function preprocessPropertyType(
|
|
48
|
-
const
|
|
81
|
+
function preprocessPropertyType(prop: ModelProperty): { type: Type; nullable: boolean } {
|
|
82
|
+
const type = prop.type;
|
|
49
83
|
|
|
50
84
|
if (type.kind === "Union") {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (nonNullVariant && nullVariant && variants.size === 2) {
|
|
55
|
-
return { type: nonNullVariant.type, nullable: true };
|
|
85
|
+
const innerType = getNullableUnionInnerType(type);
|
|
86
|
+
if (innerType) {
|
|
87
|
+
return { type: innerType, nullable: true };
|
|
56
88
|
} else {
|
|
57
|
-
return { type, nullable:
|
|
89
|
+
return { type, nullable: prop.optional };
|
|
58
90
|
}
|
|
59
91
|
} else {
|
|
60
|
-
return { type, nullable:
|
|
92
|
+
return { type, nullable: prop.optional };
|
|
61
93
|
}
|
|
62
94
|
}
|
|
@@ -1,27 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
import type
|
|
6
|
-
import { beforeEach, describe, it } from "vitest";
|
|
7
|
-
import { createEmitterFrameworkTestRunner } from "../../../test/typescript/test-host.js";
|
|
8
|
-
import { assertFileContents } from "../../../test/utils.js";
|
|
1
|
+
import { Tester } from "#test/test-host.js";
|
|
2
|
+
import { type Children } from "@alloy-js/core";
|
|
3
|
+
import { SourceFile } from "@alloy-js/csharp";
|
|
4
|
+
import type { ModelProperty } from "@typespec/compiler";
|
|
5
|
+
import { t, type TesterInstance } from "@typespec/compiler/testing";
|
|
6
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
9
7
|
import { Output } from "../../core/index.js";
|
|
10
8
|
import { ClassDeclaration } from "./class/declaration.js";
|
|
11
9
|
import { TypeExpression } from "./type-expression.jsx";
|
|
12
10
|
|
|
13
|
-
let runner:
|
|
11
|
+
let runner: TesterInstance;
|
|
14
12
|
|
|
15
13
|
beforeEach(async () => {
|
|
16
|
-
runner = await
|
|
14
|
+
runner = await Tester.createInstance();
|
|
17
15
|
});
|
|
18
16
|
|
|
19
17
|
function Wrapper(props: { children: Children }) {
|
|
20
18
|
return (
|
|
21
19
|
<Output program={runner.program}>
|
|
22
|
-
<
|
|
23
|
-
<SourceFile path="test.ts">{props.children}</SourceFile>
|
|
24
|
-
</Namespace>
|
|
20
|
+
<SourceFile path="test.ts">{props.children}</SourceFile>
|
|
25
21
|
</Output>
|
|
26
22
|
);
|
|
27
23
|
}
|
|
@@ -43,91 +39,110 @@ describe("map scalar to c# built-in types", () => {
|
|
|
43
39
|
["int64", "long"],
|
|
44
40
|
])("%s => %s", async (tspType, csType) => {
|
|
45
41
|
const type = await compileType(tspType);
|
|
46
|
-
|
|
42
|
+
expect(
|
|
47
43
|
<Wrapper>
|
|
48
44
|
<TypeExpression type={type} />
|
|
49
45
|
</Wrapper>,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
res,
|
|
54
|
-
d`
|
|
55
|
-
namespace TestNamespace
|
|
56
|
-
{
|
|
57
|
-
${csType}
|
|
58
|
-
}
|
|
59
|
-
`,
|
|
60
|
-
);
|
|
46
|
+
).toRenderTo(`
|
|
47
|
+
${csType}
|
|
48
|
+
`);
|
|
61
49
|
});
|
|
62
50
|
});
|
|
63
51
|
|
|
64
52
|
it("maps array to c# array", async () => {
|
|
65
53
|
const type = await compileType("int32[]");
|
|
66
|
-
|
|
54
|
+
expect(
|
|
67
55
|
<Wrapper>
|
|
68
56
|
<TypeExpression type={type} />
|
|
69
57
|
</Wrapper>,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
res,
|
|
74
|
-
d`
|
|
75
|
-
namespace TestNamespace
|
|
76
|
-
{
|
|
77
|
-
int[]
|
|
78
|
-
}
|
|
79
|
-
`,
|
|
80
|
-
);
|
|
58
|
+
).toRenderTo(`
|
|
59
|
+
int[]
|
|
60
|
+
`);
|
|
81
61
|
});
|
|
82
62
|
|
|
83
63
|
describe("Record map to IDictionary", () => {
|
|
84
64
|
it("for primitive types", async () => {
|
|
85
65
|
const type = await compileType("Record<int32>");
|
|
86
|
-
|
|
66
|
+
expect(
|
|
87
67
|
<Wrapper>
|
|
88
68
|
<TypeExpression type={type} />
|
|
89
69
|
</Wrapper>,
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
res,
|
|
94
|
-
d`
|
|
95
|
-
namespace TestNamespace
|
|
96
|
-
{
|
|
97
|
-
IDictionary<string, int>
|
|
98
|
-
}
|
|
99
|
-
`,
|
|
100
|
-
);
|
|
70
|
+
).toRenderTo(`
|
|
71
|
+
IDictionary<string, int>
|
|
72
|
+
`);
|
|
101
73
|
});
|
|
102
74
|
|
|
103
75
|
it("for models", async () => {
|
|
104
|
-
const { test, Pet } =
|
|
76
|
+
const { test, Pet } = await runner.compile(t.code`
|
|
105
77
|
model Test {
|
|
106
|
-
|
|
78
|
+
${t.modelProperty("test")}: Record<Pet>;
|
|
107
79
|
}
|
|
108
|
-
@test model Pet {}
|
|
109
|
-
`)
|
|
80
|
+
@test model ${t.model("Pet")} {}
|
|
81
|
+
`);
|
|
110
82
|
|
|
111
|
-
|
|
83
|
+
expect(
|
|
112
84
|
<Wrapper>
|
|
113
85
|
<ClassDeclaration type={Pet} />
|
|
114
86
|
<hbr />
|
|
115
87
|
<TypeExpression type={test.type} />
|
|
116
88
|
</Wrapper>,
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
89
|
+
).toRenderTo(`
|
|
90
|
+
class Pet
|
|
91
|
+
{
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
IDictionary<string, Pet>
|
|
95
|
+
`);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe("Nullable union", () => {
|
|
100
|
+
it("nullable boolean", async () => {
|
|
101
|
+
const { Pet } = await runner.compile(t.code`
|
|
102
|
+
@test model ${t.model("Pet")} {
|
|
103
|
+
@test name: boolean | null;
|
|
104
|
+
}
|
|
105
|
+
`);
|
|
106
|
+
|
|
107
|
+
expect(
|
|
108
|
+
<Wrapper>
|
|
109
|
+
<ClassDeclaration type={Pet} />
|
|
110
|
+
</Wrapper>,
|
|
111
|
+
).toRenderTo(`
|
|
112
|
+
class Pet
|
|
113
|
+
{
|
|
114
|
+
public required bool? name { get; set; }
|
|
115
|
+
}
|
|
116
|
+
`);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("Literal types", () => {
|
|
121
|
+
it("literal types (string, int, double, bool)", async () => {
|
|
122
|
+
const { Pet } = await runner.compile(t.code`
|
|
123
|
+
@test model ${t.model("Pet")} {
|
|
124
|
+
@test boolName: true;
|
|
125
|
+
@test intName: 42;
|
|
126
|
+
@test doubleName: 3.14;
|
|
127
|
+
@test stringName: "Hello";
|
|
128
|
+
}
|
|
129
|
+
`);
|
|
130
|
+
|
|
131
|
+
expect(
|
|
132
|
+
<Wrapper>
|
|
133
|
+
<ClassDeclaration type={Pet} />
|
|
134
|
+
</Wrapper>,
|
|
135
|
+
).toRenderTo(`
|
|
136
|
+
class Pet
|
|
137
|
+
{
|
|
138
|
+
public required bool boolName { get; set; }
|
|
139
|
+
|
|
140
|
+
public required int intName { get; set; }
|
|
141
|
+
|
|
142
|
+
public required double doubleName { get; set; }
|
|
143
|
+
|
|
144
|
+
public required string stringName { get; set; }
|
|
145
|
+
}
|
|
146
|
+
`);
|
|
132
147
|
});
|
|
133
148
|
});
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Experimental_OverridableComponent } from "#core/index.js";
|
|
2
|
+
import { code, type Children } from "@alloy-js/core";
|
|
2
3
|
import { Reference } from "@alloy-js/csharp";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getTypeName,
|
|
6
|
+
isVoidType,
|
|
7
|
+
type IntrinsicType,
|
|
8
|
+
type Scalar,
|
|
9
|
+
type Type,
|
|
10
|
+
} from "@typespec/compiler";
|
|
4
11
|
import type { Typekit } from "@typespec/compiler/typekit";
|
|
5
12
|
import { useTsp } from "../../core/index.js";
|
|
6
13
|
import { reportTypescriptDiagnostic } from "../../typescript/lib.js";
|
|
14
|
+
import { getNullableUnionInnerType } from "./utils/nullable-util.js";
|
|
7
15
|
import { efRefkey } from "./utils/refkey.js";
|
|
8
16
|
|
|
9
17
|
export interface TypeExpressionProps {
|
|
@@ -11,9 +19,19 @@ export interface TypeExpressionProps {
|
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
export function TypeExpression(props: TypeExpressionProps): Children {
|
|
22
|
+
if (props.type.kind === "Union") {
|
|
23
|
+
const nullabletype = getNullableUnionInnerType(props.type);
|
|
24
|
+
if (nullabletype) {
|
|
25
|
+
return code`${(<TypeExpression type={nullabletype} />)}?`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
14
28
|
const { $ } = useTsp();
|
|
15
29
|
if (isDeclaration($, props.type)) {
|
|
16
|
-
return
|
|
30
|
+
return (
|
|
31
|
+
<Experimental_OverridableComponent reference type={props.type}>
|
|
32
|
+
<Reference refkey={efRefkey(props.type)} />
|
|
33
|
+
</Experimental_OverridableComponent>
|
|
34
|
+
);
|
|
17
35
|
}
|
|
18
36
|
if ($.scalar.is(props.type)) {
|
|
19
37
|
return getScalarIntrinsicExpression($, props.type);
|
|
@@ -21,6 +39,15 @@ export function TypeExpression(props: TypeExpressionProps): Children {
|
|
|
21
39
|
return code`${(<TypeExpression type={props.type.indexer.value} />)}[]`;
|
|
22
40
|
} else if ($.record.is(props.type)) {
|
|
23
41
|
return code`IDictionary<string, ${(<TypeExpression type={props.type.indexer.value} />)}>`;
|
|
42
|
+
} else if ($.literal.isString(props.type)) {
|
|
43
|
+
// c# doesn't have literal types, so we map them to their corresponding C# types in general
|
|
44
|
+
return code`string`;
|
|
45
|
+
} else if ($.literal.isNumeric(props.type)) {
|
|
46
|
+
return Number.isInteger(props.type.value) ? code`int` : code`double`;
|
|
47
|
+
} else if ($.literal.isBoolean(props.type)) {
|
|
48
|
+
return code`bool`;
|
|
49
|
+
} else if (isVoidType(props.type)) {
|
|
50
|
+
return code`void`;
|
|
24
51
|
}
|
|
25
52
|
|
|
26
53
|
throw new Error(
|
|
@@ -107,8 +134,7 @@ function isDeclaration($: Typekit, type: Type): boolean {
|
|
|
107
134
|
if ($.array.is(type) || $.record.is(type)) {
|
|
108
135
|
return false;
|
|
109
136
|
}
|
|
110
|
-
|
|
111
|
-
return Boolean(type.name);
|
|
137
|
+
return true;
|
|
112
138
|
case "Union":
|
|
113
139
|
return Boolean(type.name);
|
|
114
140
|
default:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useTsp } from "#core/index.js";
|
|
2
|
+
import type { Type, Union } from "@typespec/compiler";
|
|
3
|
+
|
|
4
|
+
/** Get the inner type if the union is a nullable, otherwise return undefined */
|
|
5
|
+
export function getNullableUnionInnerType(u: Union): Type | undefined {
|
|
6
|
+
const { $ } = useTsp();
|
|
7
|
+
const isNull = (type: Type) => type === $.intrinsic.null || type === $.intrinsic.void;
|
|
8
|
+
|
|
9
|
+
if (Array.from(u.variants.values()).some((v) => isNull(v.type))) {
|
|
10
|
+
const { $ } = useTsp();
|
|
11
|
+
const left = Array.from(u.variants.values()).filter((v) => !isNull(v.type));
|
|
12
|
+
if (left.length === 0) {
|
|
13
|
+
// a union only has null or void?
|
|
14
|
+
return $.intrinsic.void;
|
|
15
|
+
} else if (left.length === 1) {
|
|
16
|
+
return left[0].type;
|
|
17
|
+
} else {
|
|
18
|
+
return $.union.create({
|
|
19
|
+
name: u.name,
|
|
20
|
+
variants: left,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
@@ -198,7 +198,12 @@ function describeScenarios(
|
|
|
198
198
|
);
|
|
199
199
|
|
|
200
200
|
if (SCENARIOS_UPDATE) {
|
|
201
|
-
|
|
201
|
+
try {
|
|
202
|
+
testBlock.content = await languageConfiguration.format(result);
|
|
203
|
+
} catch {
|
|
204
|
+
// If formatting fails, we still want to update the content
|
|
205
|
+
testBlock.content = result;
|
|
206
|
+
}
|
|
202
207
|
} else {
|
|
203
208
|
const expected = await languageConfiguration.format(testBlock.content);
|
|
204
209
|
const actual = await languageConfiguration.format(result);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type Children } from "@alloy-js/core";
|
|
2
2
|
import * as ts from "@alloy-js/typescript";
|
|
3
3
|
import { isNeverType, type ModelProperty, type Operation } from "@typespec/compiler";
|
|
4
|
-
import { getHttpPart } from "@typespec/http";
|
|
5
4
|
import { useTsp } from "../../core/context/tsp-context.js";
|
|
6
5
|
import { InterfaceMethod } from "./interface-method.jsx";
|
|
7
6
|
import { TypeExpression } from "./type-expression.js";
|
|
@@ -23,20 +22,15 @@ export function InterfaceMember(props: InterfaceMemberProps) {
|
|
|
23
22
|
return null;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
const part = getHttpPart($.program, props.type.type);
|
|
28
|
-
if (part) {
|
|
29
|
-
unpackedType = part.type;
|
|
30
|
-
}
|
|
25
|
+
const unpackedType = props.type.type;
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
);
|
|
27
|
+
const interfaceMemberProps = {
|
|
28
|
+
doc,
|
|
29
|
+
name,
|
|
30
|
+
optional: props.optional ?? props.type.optional,
|
|
31
|
+
type: <TypeExpression type={unpackedType} />,
|
|
32
|
+
};
|
|
33
|
+
return <ts.InterfaceMember {...interfaceMemberProps} />;
|
|
40
34
|
}
|
|
41
35
|
|
|
42
36
|
if ($.operation.is(props.type)) {
|
|
@@ -2,7 +2,7 @@ import { For } from "@alloy-js/core";
|
|
|
2
2
|
import { Reference, ValueExpression } from "@alloy-js/typescript";
|
|
3
3
|
import type { IntrinsicType, Model, Scalar, Type } from "@typespec/compiler";
|
|
4
4
|
import type { Typekit } from "@typespec/compiler/typekit";
|
|
5
|
-
import "
|
|
5
|
+
import { Experimental_OverridableComponent } from "../../core/components/overrides/component-overrides.jsx";
|
|
6
6
|
import { useTsp } from "../../core/context/tsp-context.js";
|
|
7
7
|
import { reportTypescriptDiagnostic } from "../../typescript/lib.js";
|
|
8
8
|
import { efRefkey } from "../utils/refkey.js";
|
|
@@ -25,11 +25,15 @@ export interface TypeExpressionProps {
|
|
|
25
25
|
|
|
26
26
|
export function TypeExpression(props: TypeExpressionProps) {
|
|
27
27
|
const { $ } = useTsp();
|
|
28
|
-
const type =
|
|
28
|
+
const type = props.type;
|
|
29
29
|
if (!props.noReference && isDeclaration($, type)) {
|
|
30
30
|
// todo: probably need abstraction around deciding what's a declaration in the output
|
|
31
31
|
// (it may not correspond to things which are declarations in TypeSpec?)
|
|
32
|
-
return
|
|
32
|
+
return (
|
|
33
|
+
<Experimental_OverridableComponent reference type={type}>
|
|
34
|
+
<Reference refkey={efRefkey(type)} />
|
|
35
|
+
</Experimental_OverridableComponent>
|
|
36
|
+
);
|
|
33
37
|
//throw new Error("Reference not implemented");
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -69,11 +73,6 @@ export function TypeExpression(props: TypeExpressionProps) {
|
|
|
69
73
|
return <RecordExpression elementType={elementType} />;
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
if ($.httpPart.is(type)) {
|
|
73
|
-
const partType = $.httpPart.unpack(type);
|
|
74
|
-
return <TypeExpression type={partType} />;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
76
|
return <InterfaceExpression type={type} />;
|
|
78
77
|
case "Operation":
|
|
79
78
|
return <FunctionType type={type} />;
|
|
@@ -227,7 +227,7 @@ export function ModelTransformExpression(props: ModelTransformExpressionProps) {
|
|
|
227
227
|
{mapJoin(
|
|
228
228
|
() => modelProperties,
|
|
229
229
|
(_, property) => {
|
|
230
|
-
const unpackedType =
|
|
230
|
+
const unpackedType = property.type;
|
|
231
231
|
let targetPropertyName = property.name;
|
|
232
232
|
let sourcePropertyName = namePolicy.getName(property.name, "interface-member");
|
|
233
233
|
|
|
@@ -368,9 +368,7 @@ export function TypeTransformCall(props: TypeTransformCallProps): Children {
|
|
|
368
368
|
}
|
|
369
369
|
const transformType = collapsedProperty?.type ?? props.type;
|
|
370
370
|
if ($.model.is(transformType) && $.array.is(transformType)) {
|
|
371
|
-
const unpackedElement =
|
|
372
|
-
$.httpPart.unpack($.array.getElementType(transformType)) ??
|
|
373
|
-
$.array.getElementType(transformType);
|
|
371
|
+
const unpackedElement = $.array.getElementType(transformType);
|
|
374
372
|
return (
|
|
375
373
|
<ts.FunctionCallExpression
|
|
376
374
|
target={ArraySerializerRefkey}
|
|
@@ -380,9 +378,7 @@ export function TypeTransformCall(props: TypeTransformCallProps): Children {
|
|
|
380
378
|
}
|
|
381
379
|
|
|
382
380
|
if ($.model.is(transformType) && $.record.is(transformType)) {
|
|
383
|
-
const unpackedElement =
|
|
384
|
-
$.httpPart.unpack($.record.getElementType(transformType)) ??
|
|
385
|
-
$.record.getElementType(transformType);
|
|
381
|
+
const unpackedElement = $.record.getElementType(transformType);
|
|
386
382
|
return (
|
|
387
383
|
<ts.FunctionCallExpression
|
|
388
384
|
target={RecordSerializerRefkey}
|