@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.
@@ -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;AAKvF,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"}
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 variants = type.variants;
73
- const nonNullVariant = [...variants.values()].find(v => v.type !== $.intrinsic.null);
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: nonNullVariant.type,
67
+ type: innerType,
78
68
  nullable: true
79
69
  };
80
70
  } else {
81
71
  return {
82
72
  type,
83
- nullable: false
73
+ nullable: prop.optional
84
74
  };
85
75
  }
86
76
  } else {
87
77
  return {
88
78
  type,
89
- nullable: false
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,EAIL,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,IAAI,EAEV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAK1D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,QAAQ,CAmCnE;AAwBD,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"}
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, isNullType, isVoidType } from "@typespec/compiler";
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,4 @@
1
+ import type { Type, Union } from "@typespec/compiler";
2
+ /** Get the inner type if the union is a nullable, otherwise return undefined */
3
+ export declare function getNullableUnionInnerType(u: Union): Type | undefined;
4
+ //# sourceMappingURL=nullable-util.d.ts.map
@@ -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.4",
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.8.2",
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 variants = type.variants;
58
- const nonNullVariant = [...variants.values()].find((v) => v.type !== $.intrinsic.null);
59
- const nullVariant = [...variants.values()].find((v) => v.type !== $.intrinsic.null);
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: false };
56
+ return { type, nullable: prop.optional };
64
57
  }
65
58
  } else {
66
- return { type, nullable: false };
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
+ }