@typespec/emitter-framework 0.11.0-dev.4 → 0.11.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.
- package/dist/src/csharp/components/property/property.d.ts.map +1 -1
- package/dist/src/csharp/components/property/property.js +6 -16
- package/dist/src/csharp/components/property/property.test.js +24 -0
- package/dist/src/csharp/components/type-expression.d.ts.map +1 -1
- package/dist/src/csharp/components/type-expression.js +2 -24
- 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 +26 -0
- package/package.json +2 -2
- package/src/csharp/components/property/property.test.tsx +22 -0
- package/src/csharp/components/property/property.tsx +6 -13
- package/src/csharp/components/type-expression.tsx +1 -24
- package/src/csharp/components/utils/nullable-util.ts +25 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"property.d.ts","sourceRoot":"","sources":["../../../../../src/csharp/components/property/property.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EAAE,KAAK,aAAa,EAAiC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"property.d.ts","sourceRoot":"","sources":["../../../../../src/csharp/components/property/property.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EAAE,KAAK,aAAa,EAAiC,MAAM,oBAAoB,CAAC;AAMvF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB,8FAA8F;IAC9F,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,QAAQ,CAiBvD;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,aAAa,CAAC;CACrB"}
|
|
@@ -5,6 +5,7 @@ import { resolveEncodedName } from "@typespec/compiler";
|
|
|
5
5
|
import { useTsp } from "../../../core/index.js";
|
|
6
6
|
import { TypeExpression } from "../type-expression.js";
|
|
7
7
|
import { getDocComments } from "../utils/doc-comments.js";
|
|
8
|
+
import { getNullableUnionInnerType } from "../utils/nullable-util.js";
|
|
8
9
|
/**
|
|
9
10
|
* Create a C# property declaration from a TypeSpec property type.
|
|
10
11
|
*/
|
|
@@ -59,34 +60,23 @@ function JsonNameAttribute(props) {
|
|
|
59
60
|
}
|
|
60
61
|
function preprocessPropertyType(prop) {
|
|
61
62
|
const type = prop.type;
|
|
62
|
-
if (prop.optional) {
|
|
63
|
-
return {
|
|
64
|
-
type,
|
|
65
|
-
nullable: true
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
const {
|
|
69
|
-
$
|
|
70
|
-
} = useTsp();
|
|
71
63
|
if (type.kind === "Union") {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const nullVariant = [...variants.values()].find(v => v.type !== $.intrinsic.null);
|
|
75
|
-
if (nonNullVariant && nullVariant && variants.size === 2) {
|
|
64
|
+
const innerType = getNullableUnionInnerType(type);
|
|
65
|
+
if (innerType) {
|
|
76
66
|
return {
|
|
77
|
-
type:
|
|
67
|
+
type: innerType,
|
|
78
68
|
nullable: true
|
|
79
69
|
};
|
|
80
70
|
} else {
|
|
81
71
|
return {
|
|
82
72
|
type,
|
|
83
|
-
nullable:
|
|
73
|
+
nullable: prop.optional
|
|
84
74
|
};
|
|
85
75
|
}
|
|
86
76
|
} else {
|
|
87
77
|
return {
|
|
88
78
|
type,
|
|
89
|
-
nullable:
|
|
79
|
+
nullable: prop.optional
|
|
90
80
|
};
|
|
91
81
|
}
|
|
92
82
|
}
|
|
@@ -84,6 +84,30 @@ it("maps optional properties to nullable properties", async () => {
|
|
|
84
84
|
}
|
|
85
85
|
`);
|
|
86
86
|
});
|
|
87
|
+
it("maps optional and nullable properties to nullable properties", async () => {
|
|
88
|
+
const {
|
|
89
|
+
prop1
|
|
90
|
+
} = await tester.compile(t.code`
|
|
91
|
+
model TestModel {
|
|
92
|
+
${t.modelProperty("prop1")}?: string | null;
|
|
93
|
+
}
|
|
94
|
+
`);
|
|
95
|
+
expect(_$createComponent(Wrapper, {
|
|
96
|
+
get children() {
|
|
97
|
+
return _$createComponent(Property, {
|
|
98
|
+
type: prop1
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
})).toRenderTo(`
|
|
102
|
+
namespace TestNamespace
|
|
103
|
+
{
|
|
104
|
+
class Test
|
|
105
|
+
{
|
|
106
|
+
public string? Prop1 { get; set; }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
`);
|
|
110
|
+
});
|
|
87
111
|
describe("jsonAttributes", () => {
|
|
88
112
|
it("adds [JsonNameAttribute]", async () => {
|
|
89
113
|
const {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-expression.d.ts","sourceRoot":"","sources":["../../../../src/csharp/components/type-expression.tsx"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,
|
|
1
|
+
{"version":3,"file":"type-expression.d.ts","sourceRoot":"","sources":["../../../../src/csharp/components/type-expression.tsx"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,IAAI,EACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAM1D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,QAAQ,CAmCnE;AAED,QAAA,MAAM,yBAAyB,4BAqC7B,CAAC;AAEH,wBAAgB,4BAA4B,CAC1C,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,MAAM,GAAG,aAAa,GAC3B,MAAM,GAAG,IAAI,CAoBf;AAyBD,OAAO,EAAE,yBAAyB,EAAE,CAAC"}
|
|
@@ -2,9 +2,10 @@ import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime
|
|
|
2
2
|
import { Experimental_OverridableComponent } from "#core/index.js";
|
|
3
3
|
import { code } from "@alloy-js/core";
|
|
4
4
|
import { Reference } from "@alloy-js/csharp";
|
|
5
|
-
import { getTypeName,
|
|
5
|
+
import { getTypeName, isVoidType } from "@typespec/compiler";
|
|
6
6
|
import { useTsp } from "../../core/index.js";
|
|
7
7
|
import { reportTypescriptDiagnostic } from "../../typescript/lib.js";
|
|
8
|
+
import { getNullableUnionInnerType } from "./utils/nullable-util.js";
|
|
8
9
|
import { efRefkey } from "./utils/refkey.js";
|
|
9
10
|
export function TypeExpression(props) {
|
|
10
11
|
if (props.type.kind === "Union") {
|
|
@@ -59,29 +60,6 @@ export function TypeExpression(props) {
|
|
|
59
60
|
}
|
|
60
61
|
throw new Error(`Unsupported type for TypeExpression: ${props.type.kind} (${getTypeName(props.type)})`);
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
-
/** Get the inner type if the union is a nullable, otherwise return undefined */
|
|
64
|
-
function getNullableUnionInnerType(u) {
|
|
65
|
-
const isNull = type => isNullType(type) || isVoidType(type);
|
|
66
|
-
if (Array.from(u.variants.values()).some(v => isNull(v.type))) {
|
|
67
|
-
const {
|
|
68
|
-
$
|
|
69
|
-
} = useTsp();
|
|
70
|
-
const left = Array.from(u.variants.values()).filter(v => !isNull(v.type));
|
|
71
|
-
if (left.length === 0) {
|
|
72
|
-
// a union only has null or void?
|
|
73
|
-
return $.intrinsic.void;
|
|
74
|
-
} else if (left.length === 1) {
|
|
75
|
-
return left[0].type;
|
|
76
|
-
} else {
|
|
77
|
-
return $.union.create({
|
|
78
|
-
name: u.name,
|
|
79
|
-
variants: left
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
63
|
const intrinsicNameToCSharpType = new Map([
|
|
86
64
|
// Core types
|
|
87
65
|
["unknown", "object"],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nullable-util.d.ts","sourceRoot":"","sources":["../../../../../src/csharp/components/utils/nullable-util.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEtD,gFAAgF;AAChF,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,CAoBpE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useTsp } from "#core/index.js";
|
|
2
|
+
/** Get the inner type if the union is a nullable, otherwise return undefined */
|
|
3
|
+
export function getNullableUnionInnerType(u) {
|
|
4
|
+
const {
|
|
5
|
+
$
|
|
6
|
+
} = useTsp();
|
|
7
|
+
const isNull = type => type === $.intrinsic.null || type === $.intrinsic.void;
|
|
8
|
+
if (Array.from(u.variants.values()).some(v => isNull(v.type))) {
|
|
9
|
+
const {
|
|
10
|
+
$
|
|
11
|
+
} = useTsp();
|
|
12
|
+
const left = Array.from(u.variants.values()).filter(v => !isNull(v.type));
|
|
13
|
+
if (left.length === 0) {
|
|
14
|
+
// a union only has null or void?
|
|
15
|
+
return $.intrinsic.void;
|
|
16
|
+
} else if (left.length === 1) {
|
|
17
|
+
return left[0].type;
|
|
18
|
+
} else {
|
|
19
|
+
return $.union.create({
|
|
20
|
+
name: u.name,
|
|
21
|
+
variants: left
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typespec/emitter-framework",
|
|
3
|
-
"version": "0.11.0-dev.
|
|
3
|
+
"version": "0.11.0-dev.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"tree-sitter-javascript": "^0.23.0",
|
|
61
61
|
"tree-sitter-python": "^0.23.2",
|
|
62
62
|
"tree-sitter-typescript": "^0.23.0",
|
|
63
|
-
"typescript": "~5.
|
|
63
|
+
"typescript": "~5.9.2",
|
|
64
64
|
"vitest": "^3.1.2",
|
|
65
65
|
"web-tree-sitter": "^0.25.4"
|
|
66
66
|
},
|
|
@@ -69,6 +69,28 @@ it("maps optional properties to nullable properties", async () => {
|
|
|
69
69
|
`);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
it("maps optional and nullable properties to nullable properties", async () => {
|
|
73
|
+
const { prop1 } = await tester.compile(t.code`
|
|
74
|
+
model TestModel {
|
|
75
|
+
${t.modelProperty("prop1")}?: string | null;
|
|
76
|
+
}
|
|
77
|
+
`);
|
|
78
|
+
|
|
79
|
+
expect(
|
|
80
|
+
<Wrapper>
|
|
81
|
+
<Property type={prop1} />
|
|
82
|
+
</Wrapper>,
|
|
83
|
+
).toRenderTo(`
|
|
84
|
+
namespace TestNamespace
|
|
85
|
+
{
|
|
86
|
+
class Test
|
|
87
|
+
{
|
|
88
|
+
public string? Prop1 { get; set; }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
`);
|
|
92
|
+
});
|
|
93
|
+
|
|
72
94
|
describe("jsonAttributes", () => {
|
|
73
95
|
it("adds [JsonNameAttribute]", async () => {
|
|
74
96
|
const { prop1 } = await tester.compile(t.code`
|
|
@@ -5,6 +5,7 @@ import { type ModelProperty, resolveEncodedName, type Type } from "@typespec/com
|
|
|
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;
|
|
@@ -47,22 +48,14 @@ function JsonNameAttribute(props: JsonNameAttributeProps): Children {
|
|
|
47
48
|
function preprocessPropertyType(prop: ModelProperty): { type: Type; nullable: boolean } {
|
|
48
49
|
const type = prop.type;
|
|
49
50
|
|
|
50
|
-
if (prop.optional) {
|
|
51
|
-
return { type, nullable: true };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const { $ } = useTsp();
|
|
55
|
-
|
|
56
51
|
if (type.kind === "Union") {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (nonNullVariant && nullVariant && variants.size === 2) {
|
|
61
|
-
return { type: nonNullVariant.type, nullable: true };
|
|
52
|
+
const innerType = getNullableUnionInnerType(type);
|
|
53
|
+
if (innerType) {
|
|
54
|
+
return { type: innerType, nullable: true };
|
|
62
55
|
} else {
|
|
63
|
-
return { type, nullable:
|
|
56
|
+
return { type, nullable: prop.optional };
|
|
64
57
|
}
|
|
65
58
|
} else {
|
|
66
|
-
return { type, nullable:
|
|
59
|
+
return { type, nullable: prop.optional };
|
|
67
60
|
}
|
|
68
61
|
}
|
|
@@ -3,16 +3,15 @@ import { code, type Children } from "@alloy-js/core";
|
|
|
3
3
|
import { Reference } from "@alloy-js/csharp";
|
|
4
4
|
import {
|
|
5
5
|
getTypeName,
|
|
6
|
-
isNullType,
|
|
7
6
|
isVoidType,
|
|
8
7
|
type IntrinsicType,
|
|
9
8
|
type Scalar,
|
|
10
9
|
type Type,
|
|
11
|
-
type Union,
|
|
12
10
|
} from "@typespec/compiler";
|
|
13
11
|
import type { Typekit } from "@typespec/compiler/typekit";
|
|
14
12
|
import { useTsp } from "../../core/index.js";
|
|
15
13
|
import { reportTypescriptDiagnostic } from "../../typescript/lib.js";
|
|
14
|
+
import { getNullableUnionInnerType } from "./utils/nullable-util.js";
|
|
16
15
|
import { efRefkey } from "./utils/refkey.js";
|
|
17
16
|
|
|
18
17
|
export interface TypeExpressionProps {
|
|
@@ -56,28 +55,6 @@ export function TypeExpression(props: TypeExpressionProps): Children {
|
|
|
56
55
|
);
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
/** Get the inner type if the union is a nullable, otherwise return undefined */
|
|
60
|
-
function getNullableUnionInnerType(u: Union): Type | undefined {
|
|
61
|
-
const isNull = (type: Type) => isNullType(type) || isVoidType(type);
|
|
62
|
-
|
|
63
|
-
if (Array.from(u.variants.values()).some((v) => isNull(v.type))) {
|
|
64
|
-
const { $ } = useTsp();
|
|
65
|
-
const left = Array.from(u.variants.values()).filter((v) => !isNull(v.type));
|
|
66
|
-
if (left.length === 0) {
|
|
67
|
-
// a union only has null or void?
|
|
68
|
-
return $.intrinsic.void;
|
|
69
|
-
} else if (left.length === 1) {
|
|
70
|
-
return left[0].type;
|
|
71
|
-
} else {
|
|
72
|
-
return $.union.create({
|
|
73
|
-
name: u.name,
|
|
74
|
-
variants: left,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return undefined;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
58
|
const intrinsicNameToCSharpType = new Map<string, string | null>([
|
|
82
59
|
// Core types
|
|
83
60
|
["unknown", "object"], // Matches C#'s `object`
|
|
@@ -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
|
+
}
|