@typespec/emitter-framework 0.11.0-dev.6 → 0.11.0-dev.7

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":"declaration.d.ts","sourceRoot":"","sources":["../../../../../src/csharp/components/class/declaration.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEvC,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAO5E,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,EAAE,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACnF,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IACxB,8FAA8F;IAC9F,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,QAAQ,CAuBvE"}
1
+ {"version":3,"file":"declaration.d.ts","sourceRoot":"","sources":["../../../../../src/csharp/components/class/declaration.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEvC,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAO5E,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,EAAE,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACnF,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,EAAE,KAAK,GAAG,SAAS,CAAC;IACxB,8FAA8F;IAC9F,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,QAAQ,CA6BvE"}
@@ -19,6 +19,13 @@ export function ClassDeclaration(props) {
19
19
  return [_$createComponent(cs.ClassDeclaration, _$mergeProps(props, {
20
20
  name: className,
21
21
  refkey: refkeys,
22
+ get baseType() {
23
+ return props.baseType ?? (props.type.kind === "Model" && props.type.baseModel ? _$createComponent(TypeExpression, {
24
+ get type() {
25
+ return props.type.baseModel;
26
+ }
27
+ }) : undefined);
28
+ },
22
29
  get doc() {
23
30
  return getDocComments($, props.type);
24
31
  },
@@ -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;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"}
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;AAMpG,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,CAkDvD;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,aAAa,CAAC;CACrB"}
@@ -1,7 +1,7 @@
1
1
  import { memo as _$memo, createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
2
2
  import * as cs from "@alloy-js/csharp";
3
3
  import { Attribute } from "@alloy-js/csharp";
4
- import { resolveEncodedName } from "@typespec/compiler";
4
+ import { getProperty, 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";
@@ -14,6 +14,31 @@ export function Property(props) {
14
14
  const {
15
15
  $
16
16
  } = useTsp();
17
+ let overrideType = "";
18
+ let isVirtual = false;
19
+ if (props.type.model) {
20
+ if (props.type.model.baseModel) {
21
+ const base = props.type.model.baseModel;
22
+ const baseProperty = getProperty(base, props.type.name);
23
+ if (baseProperty) {
24
+ const baseResult = preprocessPropertyType(baseProperty);
25
+ if (baseResult.nullable === result.nullable && baseResult.type === result.type) {
26
+ overrideType = "override";
27
+ } else {
28
+ overrideType = "new";
29
+ }
30
+ }
31
+ }
32
+ if (overrideType === "" && props.type.model.derivedModels && props.type.model.derivedModels.length > 0) {
33
+ isVirtual = props.type.model.derivedModels.some(derived => {
34
+ const derivedProperty = derived.properties.get(props.type.name);
35
+ if (derivedProperty) {
36
+ const derivedResult = preprocessPropertyType(derivedProperty);
37
+ return derivedResult.nullable === result.nullable && derivedResult.type === result.type;
38
+ }
39
+ });
40
+ }
41
+ }
17
42
  return _$createComponent(cs.Property, {
18
43
  get name() {
19
44
  return props.type.name;
@@ -25,7 +50,10 @@ export function Property(props) {
25
50
  }
26
51
  });
27
52
  },
53
+ override: overrideType === "override",
54
+ "new": overrideType === "new",
28
55
  "public": true,
56
+ virtual: isVirtual,
29
57
  get required() {
30
58
  return !props.type.optional;
31
59
  },
@@ -1,5 +1,6 @@
1
1
  import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
2
2
  import { Tester } from "#test/test-host.js";
3
+ import { List } from "@alloy-js/core";
3
4
  import { ClassDeclaration, createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
4
5
  import { t } from "@typespec/compiler/testing";
5
6
  import { beforeEach, describe, expect, it } from "vitest";
@@ -162,4 +163,80 @@ describe("jsonAttributes", () => {
162
163
  }
163
164
  `);
164
165
  });
166
+ it("inherit prop: override, new", async () => {
167
+ const r = await tester.compile(t.code`
168
+ model TestModel extends BaseModel {
169
+ ${t.modelProperty("prop1")}: string;
170
+ ${t.modelProperty("prop2")}: string | null;
171
+ }
172
+ model BaseModel {
173
+ prop1: string | null;
174
+ prop2: string | null;
175
+ }
176
+ `);
177
+ expect(_$createComponent(Wrapper, {
178
+ get children() {
179
+ return _$createComponent(List, {
180
+ get children() {
181
+ return [_$createComponent(Property, {
182
+ get type() {
183
+ return r.prop1;
184
+ }
185
+ }), _$createComponent(Property, {
186
+ get type() {
187
+ return r.prop2;
188
+ }
189
+ })];
190
+ }
191
+ });
192
+ }
193
+ })).toRenderTo(`
194
+ namespace TestNamespace
195
+ {
196
+ class Test
197
+ {
198
+ public new required string Prop1 { get; set; }
199
+ public override required string? Prop2 { get; set; }
200
+ }
201
+ }
202
+ `);
203
+ });
204
+ it("inherit prop: virtual", async () => {
205
+ const r = await tester.compile(t.code`
206
+ model TestModel extends BaseModel {
207
+ prop1: string;
208
+ prop2: string | null;
209
+ }
210
+ model BaseModel {
211
+ ${t.modelProperty("prop1")}: string | null;
212
+ ${t.modelProperty("prop2")}: string | null;
213
+ }
214
+ `);
215
+ expect(_$createComponent(Wrapper, {
216
+ get children() {
217
+ return _$createComponent(List, {
218
+ get children() {
219
+ return [_$createComponent(Property, {
220
+ get type() {
221
+ return r.prop1;
222
+ }
223
+ }), _$createComponent(Property, {
224
+ get type() {
225
+ return r.prop2;
226
+ }
227
+ })];
228
+ }
229
+ });
230
+ }
231
+ })).toRenderTo(`
232
+ namespace TestNamespace
233
+ {
234
+ class Test
235
+ {
236
+ public required string? Prop1 { get; set; }
237
+ public virtual required string? Prop2 { get; set; }
238
+ }
239
+ }
240
+ `);
241
+ });
165
242
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/emitter-framework",
3
- "version": "0.11.0-dev.6",
3
+ "version": "0.11.0-dev.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -41,6 +41,12 @@ export function ClassDeclaration(props: ClassDeclarationProps): Children {
41
41
  {...props}
42
42
  name={className}
43
43
  refkey={refkeys}
44
+ baseType={
45
+ props.baseType ??
46
+ (props.type.kind === "Model" && props.type.baseModel ? (
47
+ <TypeExpression type={props.type.baseModel} />
48
+ ) : undefined)
49
+ }
44
50
  doc={getDocComments($, props.type)}
45
51
  >
46
52
  {props.type.kind === "Model" && (
@@ -1,5 +1,5 @@
1
1
  import { Tester } from "#test/test-host.js";
2
- import { type Children } from "@alloy-js/core";
2
+ import { List, type Children } from "@alloy-js/core";
3
3
  import { ClassDeclaration, createCSharpNamePolicy, Namespace, SourceFile } from "@alloy-js/csharp";
4
4
  import { t, type TesterInstance } from "@typespec/compiler/testing";
5
5
  import { beforeEach, describe, expect, it } from "vitest";
@@ -138,4 +138,66 @@ describe("jsonAttributes", () => {
138
138
  }
139
139
  `);
140
140
  });
141
+
142
+ it("inherit prop: override, new", async () => {
143
+ const r = await tester.compile(t.code`
144
+ model TestModel extends BaseModel {
145
+ ${t.modelProperty("prop1")}: string;
146
+ ${t.modelProperty("prop2")}: string | null;
147
+ }
148
+ model BaseModel {
149
+ prop1: string | null;
150
+ prop2: string | null;
151
+ }
152
+ `);
153
+
154
+ expect(
155
+ <Wrapper>
156
+ <List>
157
+ <Property type={r.prop1} />
158
+ <Property type={r.prop2} />
159
+ </List>
160
+ </Wrapper>,
161
+ ).toRenderTo(`
162
+ namespace TestNamespace
163
+ {
164
+ class Test
165
+ {
166
+ public new required string Prop1 { get; set; }
167
+ public override required string? Prop2 { get; set; }
168
+ }
169
+ }
170
+ `);
171
+ });
172
+
173
+ it("inherit prop: virtual", async () => {
174
+ const r = await tester.compile(t.code`
175
+ model TestModel extends BaseModel {
176
+ prop1: string;
177
+ prop2: string | null;
178
+ }
179
+ model BaseModel {
180
+ ${t.modelProperty("prop1")}: string | null;
181
+ ${t.modelProperty("prop2")}: string | null;
182
+ }
183
+ `);
184
+
185
+ expect(
186
+ <Wrapper>
187
+ <List>
188
+ <Property type={r.prop1} />
189
+ <Property type={r.prop2} />
190
+ </List>
191
+ </Wrapper>,
192
+ ).toRenderTo(`
193
+ namespace TestNamespace
194
+ {
195
+ class Test
196
+ {
197
+ public required string? Prop1 { get; set; }
198
+ public virtual required string? Prop2 { get; set; }
199
+ }
200
+ }
201
+ `);
202
+ });
141
203
  });
@@ -1,7 +1,7 @@
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";
@@ -20,11 +20,44 @@ export function Property(props: PropertyProps): Children {
20
20
  const result = preprocessPropertyType(props.type);
21
21
  const { $ } = useTsp();
22
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
+
23
53
  return (
24
54
  <cs.Property
25
55
  name={props.type.name}
26
56
  type={<TypeExpression type={result.type} />}
57
+ override={overrideType === "override"}
58
+ new={overrideType === "new"}
27
59
  public
60
+ virtual={isVirtual}
28
61
  required={!props.type.optional}
29
62
  nullable={result.nullable}
30
63
  doc={getDocComments($, props.type)}