From 4c0f22dd38f44eebf8b726cfa7b4dfa131578fc6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 03:28:08 +0000 Subject: [PATCH 1/9] Initial plan From ce03a0ad482d940e6695210ad23c91d97bf3c67f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 03:49:51 +0000 Subject: [PATCH 2/9] Add External property to InputType to align with TCGC Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../emitter/src/lib/type-converter.ts | 71 ++++++++++--------- .../emitter/src/type/input-type.ts | 11 +++ .../emitter/test/Unit/type-converter.test.ts | 25 ++++--- .../src/InputTypes/ExternalTypeInfo.cs | 39 ++++++++++ .../src/InputTypes/InputType.cs | 1 + .../ExternalTypeInfoConverter.cs | 63 ++++++++++++++++ .../Serialization/InputArrayTypeConverter.cs | 7 +- .../InputDictionaryTypeConverter.cs | 5 +- .../Serialization/InputUnionTypeConverter.cs | 5 +- 9 files changed, 181 insertions(+), 46 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs diff --git a/packages/http-client-csharp/emitter/src/lib/type-converter.ts b/packages/http-client-csharp/emitter/src/lib/type-converter.ts index f49918d1fc6..6c0ea9408fb 100644 --- a/packages/http-client-csharp/emitter/src/lib/type-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/type-converter.ts @@ -38,6 +38,7 @@ import { InputPrimitiveType, InputType, InputUnionType, + ExternalTypeInfo, } from "../type/input-type.js"; import { isReadOnly } from "./utils.js"; @@ -81,12 +82,14 @@ export function fromSdkType( return retVar as any; } - // Check if this type references an external type - if ((sdkType as any).external) { - retVar = fromSdkExternalType(sdkContext, sdkType); - sdkContext.__typeCache.updateSdkTypeReferences(sdkType, retVar); - return retVar as any; - } + // Extract external type information if present + const externalInfo = (sdkType as any).external + ? { + identity: (sdkType as any).external.identity, + package: (sdkType as any).external.package, + minVersion: (sdkType as any).external.minVersion, + } + : undefined; switch (sdkType.kind) { case "nullable": @@ -94,23 +97,24 @@ export function fromSdkType( kind: "nullable", type: fromSdkType(sdkContext, sdkType.type, sdkProperty, namespace), namespace: sdkType.namespace, + external: externalInfo, }; retVar = nullableType; break; case "model": - retVar = fromSdkModelType(sdkContext, sdkType); + retVar = fromSdkModelType(sdkContext, sdkType, externalInfo); break; case "enum": - retVar = fromSdkEnumType(sdkContext, sdkType); + retVar = fromSdkEnumType(sdkContext, sdkType, externalInfo); break; case "enumvalue": retVar = fromSdkEnumValueType(sdkContext, sdkType); break; case "dict": - retVar = fromSdkDictionaryType(sdkContext, sdkType); + retVar = fromSdkDictionaryType(sdkContext, sdkType, externalInfo); break; case "array": - retVar = fromSdkArrayType(sdkContext, sdkType); + retVar = fromSdkArrayType(sdkContext, sdkType, externalInfo); break; case "constant": if ( @@ -120,20 +124,20 @@ export function fromSdkType( sdkType.valueType.kind !== "boolean" ) { // turn the constant into an extensible enum - retVar = createEnumType(sdkContext, sdkType, namespace!); + retVar = createEnumType(sdkContext, sdkType, namespace!, externalInfo); } else { retVar = fromSdkConstantType(sdkContext, sdkType); } break; case "union": - retVar = fromUnionType(sdkContext, sdkType); + retVar = fromUnionType(sdkContext, sdkType, externalInfo); break; case "utcDateTime": case "offsetDateTime": - retVar = fromSdkDateTimeType(sdkContext, sdkType); + retVar = fromSdkDateTimeType(sdkContext, sdkType, externalInfo); break; case "duration": - retVar = fromSdkDurationType(sdkContext, sdkType); + retVar = fromSdkDurationType(sdkContext, sdkType, externalInfo); break; case "tuple": sdkContext.logger.reportDiagnostic({ @@ -146,6 +150,7 @@ export function fromSdkType( name: "tuple", crossLanguageDefinitionId: "", decorators: sdkType.decorators, + external: externalInfo, }; retVar = tupleType; break; @@ -165,11 +170,12 @@ export function fromSdkType( name: "credential", crossLanguageDefinitionId: "", decorators: sdkType.decorators, + external: externalInfo, }; retVar = credentialType; break; default: - retVar = fromSdkBuiltInType(sdkContext, sdkType); + retVar = fromSdkBuiltInType(sdkContext, sdkType, externalInfo); break; } @@ -181,6 +187,7 @@ export function fromSdkType( function fromSdkModelType( sdkContext: CSharpEmitterContext, modelType: SdkModelType, + externalInfo?: ExternalTypeInfo, ): InputModelType { // get all unique decorators for the model type from the namespace level and the model level let decorators: DecoratorInfo[] = modelType.decorators; @@ -200,6 +207,7 @@ function fromSdkModelType( summary: modelType.summary, discriminatorValue: modelType.discriminatorValue, decorators: decorators, + external: externalInfo, } as InputModelType; sdkContext.__typeCache.updateSdkTypeReferences(modelType, inputModelType); @@ -281,14 +289,15 @@ function fromSdkModelProperty( return property; } -function fromSdkEnumType(sdkContext: CSharpEmitterContext, enumType: SdkEnumType): InputEnumType { - return createEnumType(sdkContext, enumType, enumType.namespace); +function fromSdkEnumType(sdkContext: CSharpEmitterContext, enumType: SdkEnumType, externalInfo?: ExternalTypeInfo): InputEnumType { + return createEnumType(sdkContext, enumType, enumType.namespace, externalInfo); } function createEnumType( sdkContext: CSharpEmitterContext, sdkType: SdkConstantType | SdkEnumType, namespace: string, + externalInfo?: ExternalTypeInfo, ): InputEnumType { const values: InputEnumValueType[] = []; @@ -313,6 +322,7 @@ function createEnumType( // constantType.usage, TODO - constant type now does not have usage. TCGC will add it later usage: sdkType.kind === "enum" ? sdkType.usage : UsageFlags.None, decorators: sdkType.decorators, + external: externalInfo, }; sdkContext.__typeCache.updateSdkTypeReferences(sdkType, inputEnumType); @@ -331,6 +341,7 @@ function createEnumType( function fromSdkDateTimeType( sdkContext: CSharpEmitterContext, dateTimeType: SdkDateTimeType, + externalInfo?: ExternalTypeInfo, ): InputDateTimeType { return { kind: dateTimeType.kind, @@ -340,12 +351,14 @@ function fromSdkDateTimeType( crossLanguageDefinitionId: dateTimeType.crossLanguageDefinitionId, baseType: dateTimeType.baseType ? fromSdkType(sdkContext, dateTimeType.baseType) : undefined, decorators: dateTimeType.decorators, + external: externalInfo, }; } function fromSdkDurationType( sdkContext: CSharpEmitterContext, durationType: SdkDurationType, + externalInfo?: ExternalTypeInfo, ): InputDurationType { return { kind: durationType.kind, @@ -355,12 +368,14 @@ function fromSdkDurationType( crossLanguageDefinitionId: durationType.crossLanguageDefinitionId, baseType: durationType.baseType ? fromSdkType(sdkContext, durationType.baseType) : undefined, decorators: durationType.decorators, + external: externalInfo, }; } function fromSdkBuiltInType( sdkContext: CSharpEmitterContext, builtInType: SdkBuiltInType, + externalInfo?: ExternalTypeInfo, ): InputPrimitiveType { return { kind: builtInType.kind, @@ -369,10 +384,11 @@ function fromSdkBuiltInType( crossLanguageDefinitionId: builtInType.crossLanguageDefinitionId, baseType: builtInType.baseType ? fromSdkType(sdkContext, builtInType.baseType) : undefined, decorators: builtInType.decorators, + external: externalInfo, }; } -function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType): InputUnionType { +function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType, externalInfo?: ExternalTypeInfo): InputUnionType { const variantTypes: InputType[] = []; for (const value of union.variantTypes) { const variantType = fromSdkType(sdkContext, value); @@ -385,6 +401,7 @@ function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType): I variantTypes: variantTypes, namespace: union.namespace, decorators: union.decorators, + external: externalInfo, }; } @@ -441,18 +458,21 @@ function createEnumValueType( function fromSdkDictionaryType( sdkContext: CSharpEmitterContext, dictionaryType: SdkDictionaryType, + externalInfo?: ExternalTypeInfo, ): InputDictionaryType { return { kind: "dict", keyType: fromSdkType(sdkContext, dictionaryType.keyType), valueType: fromSdkType(sdkContext, dictionaryType.valueType), decorators: dictionaryType.decorators, + external: externalInfo, }; } function fromSdkArrayType( sdkContext: CSharpEmitterContext, arrayType: SdkArrayType, + externalInfo?: ExternalTypeInfo, ): InputArrayType { return { kind: "array", @@ -460,6 +480,7 @@ function fromSdkArrayType( valueType: fromSdkType(sdkContext, arrayType.valueType), crossLanguageDefinitionId: arrayType.crossLanguageDefinitionId, decorators: arrayType.decorators, + external: externalInfo, }; } @@ -471,20 +492,6 @@ function fromSdkEndpointType(): InputPrimitiveType { }; } -function fromSdkExternalType( - sdkContext: CSharpEmitterContext, - sdkType: SdkType, -): InputExternalType { - const external = (sdkType as any).external; - return { - kind: "external", - identity: external.identity, - package: external.package, - minVersion: external.minVersion, - decorators: sdkType.decorators, - }; -} - /** * @beta */ diff --git a/packages/http-client-csharp/emitter/src/type/input-type.ts b/packages/http-client-csharp/emitter/src/type/input-type.ts index 4164350ea21..0523664d7fa 100644 --- a/packages/http-client-csharp/emitter/src/type/input-type.ts +++ b/packages/http-client-csharp/emitter/src/type/input-type.ts @@ -16,6 +16,16 @@ import { InputParameterScope } from "./input-parameter-scope.js"; import { InputServiceMethod } from "./input-service-method.js"; import { RequestLocation } from "./request-location.js"; +/** + * External type information for types that map to external library types. + * @beta + */ +export interface ExternalTypeInfo { + identity: string; + package?: string; + minVersion?: string; +} + /** * The input client type for the CSharp emitter. * @beta @@ -54,6 +64,7 @@ interface InputTypeBase extends DecoratedType { summary?: string; doc?: string; deprecation?: string; + external?: ExternalTypeInfo; } export type InputType = diff --git a/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts b/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts index abe4b08e49e..931a5fdc58f 100644 --- a/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts +++ b/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts @@ -127,11 +127,15 @@ describe("External types", () => { const prop = testModel.properties.find((p) => p.name === "prop"); ok(prop, "prop should exist"); - // The type should be an external type - strictEqual(prop.type.kind, "external"); - strictEqual((prop.type as any).identity, "Azure.Core.Expressions.DataFactoryExpression"); - strictEqual((prop.type as any).package, "Azure.Core.Expressions"); - strictEqual((prop.type as any).minVersion, "1.0.0"); + // The type should remain a union but with external info + strictEqual(prop.type.kind, "union"); + ok((prop.type as any).external, "Type should have external info"); + strictEqual((prop.type as any).external.identity, "Azure.Core.Expressions.DataFactoryExpression"); + strictEqual((prop.type as any).external.package, "Azure.Core.Expressions"); + strictEqual((prop.type as any).external.minVersion, "1.0.0"); + // Verify union variants are preserved + ok((prop.type as any).variantTypes, "Union should have variant types"); + strictEqual((prop.type as any).variantTypes.length, 2, "Union should have 2 variant types"); }); it("should convert external type on model", async () => { @@ -165,10 +169,11 @@ describe("External types", () => { const jsonElementProp = testModel.properties.find((p) => p.name === "jsonElement"); ok(jsonElementProp, "jsonElement property should exist"); - // The type should be an external type - strictEqual(jsonElementProp.type.kind, "external"); - strictEqual((jsonElementProp.type as any).identity, "System.Text.Json.JsonElement"); - strictEqual((jsonElementProp.type as any).package, "System.Text.Json"); - strictEqual((jsonElementProp.type as any).minVersion, "8.0.0"); + // The type should remain a model but with external info + strictEqual(jsonElementProp.type.kind, "model"); + ok((jsonElementProp.type as any).external, "Type should have external info"); + strictEqual((jsonElementProp.type as any).external.identity, "System.Text.Json.JsonElement"); + strictEqual((jsonElementProp.type as any).external.package, "System.Text.Json"); + strictEqual((jsonElementProp.type as any).external.minVersion, "8.0.0"); }); }); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs new file mode 100644 index 00000000000..781a949cacf --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.TypeSpec.Generator.Input +{ + /// + /// External type information for types that map to external library types. + /// + public sealed class ExternalTypeInfo + { + /// + /// Construct a new instance + /// + /// The fully qualified name of the external type. + /// The package that exports the external type. + /// The minimum version of the package. + public ExternalTypeInfo(string identity, string? package, string? minVersion) + { + Identity = identity; + Package = package; + MinVersion = minVersion; + } + + /// + /// The fully qualified name of the external type. For example, "Azure.Core.Expressions.DataFactoryExpression" + /// + public string Identity { get; } + + /// + /// The package that exports the external type. For example, "Azure.Core.Expressions" + /// + public string? Package { get; } + + /// + /// The minimum version of the package to use for the external type. For example, "1.0.0" + /// + public string? MinVersion { get; } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs index efafe4186e3..a1a1d551629 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs @@ -21,6 +21,7 @@ protected InputType(string name) public string Name { get; internal set; } public IReadOnlyList Decorators { get; internal set; } = new List(); + public ExternalTypeInfo? External { get; internal set; } internal InputType GetCollectionEquivalent(InputType inputType) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs new file mode 100644 index 00000000000..1c5a91627fa --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Microsoft.TypeSpec.Generator.Input +{ + internal class ExternalTypeInfoConverter : JsonConverter + { + private readonly TypeSpecReferenceHandler _referenceHandler; + + public ExternalTypeInfoConverter(TypeSpecReferenceHandler referenceHandler) + { + _referenceHandler = referenceHandler; + } + + public override ExternalTypeInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateExternalTypeInfo(ref reader, null, options, _referenceHandler.CurrentResolver); + } + + public override void Write(Utf8JsonWriter writer, ExternalTypeInfo value, JsonSerializerOptions options) + => throw new NotSupportedException("Writing not supported"); + + public static ExternalTypeInfo CreateExternalTypeInfo(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) + { + string? identity = null; + string? package = null; + string? minVersion = null; + + while (reader.TokenType != JsonTokenType.EndObject) + { + var isKnownProperty = reader.TryReadReferenceId(ref id) + || reader.TryReadString("identity", ref identity) + || reader.TryReadString("package", ref package) + || reader.TryReadString("minVersion", ref minVersion); + + if (!isKnownProperty) + { + reader.SkipProperty(); + } + } + + identity = identity ?? throw new JsonException("ExternalTypeInfo must have identity"); + + var externalTypeInfo = new ExternalTypeInfo(identity, package, minVersion); + + if (id != null) + { + resolver.AddReference(id, externalTypeInfo); + } + + return externalTypeInfo; + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs index b27cfd575dd..8f9e1fe7ff7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs @@ -28,13 +28,15 @@ public static InputArrayType CreateListType(ref Utf8JsonReader reader, string? i string? crossLanguageDefinitionId = null; InputType? valueType = null; IReadOnlyList? decorators = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadString("name", ref name) || reader.TryReadString("crossLanguageDefinitionId", ref crossLanguageDefinitionId) || reader.TryReadComplexType("valueType", options, ref valueType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -45,7 +47,8 @@ public static InputArrayType CreateListType(ref Utf8JsonReader reader, string? i valueType = valueType ?? throw new JsonException("List must have element type"); var listType = new InputArrayType(name ?? "Array", crossLanguageDefinitionId ?? string.Empty, valueType) { - Decorators = decorators ?? [] + Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs index 4a7737426a6..43a5816c4c2 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs @@ -28,12 +28,14 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader InputType? keyType = null; InputType? valueType = null; IReadOnlyList? decorators = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadComplexType("keyType", options, ref keyType) || reader.TryReadComplexType("valueType", options, ref valueType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -47,6 +49,7 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader var dictType = new InputDictionaryType("Dictionary", keyType, valueType) { Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs index b286b20d6bd..2c717b8ff2e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs @@ -37,11 +37,13 @@ public static InputUnionType CreateInputUnionType(ref Utf8JsonReader reader, str IReadOnlyList? variantTypes = null; IReadOnlyList? decorators = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) || reader.TryReadComplexType("variantTypes", options, ref variantTypes) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -56,6 +58,7 @@ public static InputUnionType CreateInputUnionType(ref Utf8JsonReader reader, str } union.VariantTypes = variantTypes; union.Decorators = decorators ?? []; + union.External = external; return union; } } From 2276ef1515dde41950f639bca60550e54b4f9641 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 03:54:14 +0000 Subject: [PATCH 3/9] Update type converters to handle External property Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../InputTypes/Serialization/InputDateTimeTypeConverter.cs | 6 ++++-- .../InputTypes/Serialization/InputDurationTypeConverter.cs | 6 ++++-- .../src/InputTypes/Serialization/InputModelTypeConverter.cs | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs index 1ebb73d5971..016a3c49167 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs @@ -29,6 +29,7 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDateTimeType? baseType = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -38,7 +39,8 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st || reader.TryReadString("encode", ref encode) || reader.TryReadComplexType("wireType", options, ref wireType) || reader.TryReadComplexType("baseType", options, ref baseType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -52,7 +54,7 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st wireType = wireType ?? throw new JsonException("DateTime type must have wireType"); var dateTimeType = Enum.TryParse(encode, ignoreCase: true, out var encodeKind) - ? new InputDateTimeType(encodeKind, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [] } + ? new InputDateTimeType(encodeKind, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [], External = external } : throw new JsonException($"Encoding of DateTime type {encode} is unknown."); if (id != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs index 789571e7302..7e7ad4cdbd5 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs @@ -30,6 +30,7 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDurationType? baseType = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { @@ -39,7 +40,8 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st || reader.TryReadString("encode", ref encode) || reader.TryReadComplexType("wireType", options, ref wireType) || reader.TryReadComplexType("baseType", options, ref baseType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -53,7 +55,7 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st wireType = wireType ?? throw new JsonException("Duration type must have wireType"); var dateTimeType = DurationKnownEncodingExtensions.TryParse(encode, out var encodeKind) - ? new InputDurationType(encodeKind.Value, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [] } + ? new InputDurationType(encodeKind.Value, name, crossLanguageDefinitionId, wireType, baseType) { Decorators = decorators ?? [], External = external } : throw new JsonException($"Encoding of Duration type {encode} is unknown."); if (id != null) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs index 18b691d77e7..20274b3c976 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs @@ -72,6 +72,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string bool modelAsStruct = false; IReadOnlyList? decorators = null; InputSerializationOptions? serializationOptions = null; + ExternalTypeInfo? external = null; // read all possible properties and throw away the unknown properties while (reader.TokenType != JsonTokenType.EndObject) @@ -92,6 +93,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string || reader.TryReadComplexType("discriminatedSubtypes", options, ref discriminatedSubtypes) || reader.TryReadComplexType("decorators", options, ref decorators) || reader.TryReadComplexType("serializationOptions", options, ref serializationOptions) + || reader.TryReadComplexType("external", options, ref external) || reader.TryReadBoolean(nameof(InputModelType.ModelAsStruct), ref modelAsStruct); // TODO -- change this to fetch from the decorator list instead when the decorator is ready if (!isKnownProperty) @@ -138,6 +140,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string MarkModelsAsDynamicRecursive(model, []); } } + model.External = external; // if this model has a base, it means this model is a derived model of the base model, add it into the list. if (baseModel != null) From ff10ef140f271ad7e810e165a7bc04f53a09fc1c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 03:57:47 +0000 Subject: [PATCH 4/9] Complete External property support for all InputType converters Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../src/InputTypes/Serialization/InputEnumTypeConverter.cs | 5 ++++- .../Serialization/InputPrimitiveTypeConverter.cs | 7 +++++-- .../Serialization/TypeSpecInputNullableTypeConverter.cs | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs index fa3fc2246b3..af12ead633e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs @@ -60,6 +60,7 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id InputPrimitiveType? valueType = null; IReadOnlyList? values = null; IReadOnlyList? decorators = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) @@ -73,7 +74,8 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id || reader.TryReadBoolean("isFixed", ref isFixed) || reader.TryReadComplexType("valueType", options, ref valueType) || reader.TryReadComplexType("values", options, ref values) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -97,6 +99,7 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id enumType.ValueType = valueType ?? throw new JsonException("Enum must have valueType"); enumType.IsExtensible = !isFixed; enumType.Decorators = decorators ?? []; + enumType.External = external; return enumType; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs index 61c6b7e6cd2..1ef4bb6418c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs @@ -29,6 +29,7 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, string? encode = null; InputPrimitiveType? baseType = null; IReadOnlyList? decorators = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) @@ -37,7 +38,8 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, || reader.TryReadString("crossLanguageDefinitionId", ref crossLanguageDefinitionId) || reader.TryReadString("encode", ref encode) || reader.TryReadComplexType("baseType", options, ref baseType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -56,7 +58,8 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, var primitiveType = new InputPrimitiveType(primitiveTypeKind, name, crossLanguageDefinitionId, encode, baseType) { - Decorators = decorators ?? [] + Decorators = decorators ?? [], + External = external }; if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs index 815a946dc21..f56a9bfc210 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs @@ -26,12 +26,14 @@ public static InputNullableType CreateNullableType(ref Utf8JsonReader reader, st { InputType? valueType = null; IReadOnlyList? decorators = null; + ExternalTypeInfo? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) || reader.TryReadString("name", ref name) || reader.TryReadComplexType("type", options, ref valueType) - || reader.TryReadComplexType("decorators", options, ref decorators); + || reader.TryReadComplexType("decorators", options, ref decorators) + || reader.TryReadComplexType("external", options, ref external); if (!isKnownProperty) { @@ -44,6 +46,7 @@ public static InputNullableType CreateNullableType(ref Utf8JsonReader reader, st var nullableType = new InputNullableType(valueType) { Decorators = decorators ?? [], + External = external }; if (id != null) { From 8075dd5d95efb51ca4ca4ca7d0a631a42716d8f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 04:22:57 +0000 Subject: [PATCH 5/9] Refactor external type handling based on feedback - Renamed ExternalTypeInfo to InputExternalTypeProperties - Created fromSdkExternalTypeInfo helper function instead of extracting inline - Removed externalInfo parameter from all helper functions - Deleted InputExternalType class and converter - Updated TypeFactory to check External property and call CreateExternalType - Updated tests to use new ExternalUnion helper Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../emitter/src/lib/type-converter.ts | 83 ++++++++++--------- .../emitter/src/type/input-type.ts | 14 +--- .../src/InputTypes/InputExternalType.cs | 39 --------- ...Info.cs => InputExternalTypeProperties.cs} | 6 +- .../src/InputTypes/InputType.cs | 2 +- .../Serialization/InputArrayTypeConverter.cs | 2 +- .../InputDateTimeTypeConverter.cs | 2 +- .../InputDictionaryTypeConverter.cs | 2 +- .../InputDurationTypeConverter.cs | 2 +- .../Serialization/InputEnumTypeConverter.cs | 2 +- .../InputExternalTypeConverter.cs | 62 -------------- ...> InputExternalTypePropertiesConverter.cs} | 20 ++--- .../Serialization/InputModelTypeConverter.cs | 2 +- .../InputPrimitiveTypeConverter.cs | 2 +- .../Serialization/InputTypeConverter.cs | 2 - .../Serialization/InputUnionTypeConverter.cs | 2 +- .../TypeSpecInputNullableTypeConverter.cs | 2 +- .../src/TypeFactory.cs | 19 +++-- .../ModelProviders/ModelProviderTests.cs | 6 +- .../test/common/InputFactory.cs | 6 +- 20 files changed, 86 insertions(+), 191 deletions(-) delete mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/{ExternalTypeInfo.cs => InputExternalTypeProperties.cs} (84%) delete mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/{ExternalTypeInfoConverter.cs => InputExternalTypePropertiesConverter.cs} (51%) diff --git a/packages/http-client-csharp/emitter/src/lib/type-converter.ts b/packages/http-client-csharp/emitter/src/lib/type-converter.ts index 6c0ea9408fb..6f47c003f1d 100644 --- a/packages/http-client-csharp/emitter/src/lib/type-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/type-converter.ts @@ -29,7 +29,6 @@ import { InputDurationType, InputEnumType, InputEnumValueType, - InputExternalType, InputLiteralType, InputModelProperty, InputModelType, @@ -38,7 +37,7 @@ import { InputPrimitiveType, InputType, InputUnionType, - ExternalTypeInfo, + InputExternalTypeProperties, } from "../type/input-type.js"; import { isReadOnly } from "./utils.js"; @@ -82,39 +81,30 @@ export function fromSdkType( return retVar as any; } - // Extract external type information if present - const externalInfo = (sdkType as any).external - ? { - identity: (sdkType as any).external.identity, - package: (sdkType as any).external.package, - minVersion: (sdkType as any).external.minVersion, - } - : undefined; - switch (sdkType.kind) { case "nullable": const nullableType: InputNullableType = { kind: "nullable", type: fromSdkType(sdkContext, sdkType.type, sdkProperty, namespace), namespace: sdkType.namespace, - external: externalInfo, + external: fromSdkExternalTypeInfo(sdkType), }; retVar = nullableType; break; case "model": - retVar = fromSdkModelType(sdkContext, sdkType, externalInfo); + retVar = fromSdkModelType(sdkContext, sdkType); break; case "enum": - retVar = fromSdkEnumType(sdkContext, sdkType, externalInfo); + retVar = fromSdkEnumType(sdkContext, sdkType); break; case "enumvalue": retVar = fromSdkEnumValueType(sdkContext, sdkType); break; case "dict": - retVar = fromSdkDictionaryType(sdkContext, sdkType, externalInfo); + retVar = fromSdkDictionaryType(sdkContext, sdkType); break; case "array": - retVar = fromSdkArrayType(sdkContext, sdkType, externalInfo); + retVar = fromSdkArrayType(sdkContext, sdkType); break; case "constant": if ( @@ -124,20 +114,20 @@ export function fromSdkType( sdkType.valueType.kind !== "boolean" ) { // turn the constant into an extensible enum - retVar = createEnumType(sdkContext, sdkType, namespace!, externalInfo); + retVar = createEnumType(sdkContext, sdkType, namespace!); } else { retVar = fromSdkConstantType(sdkContext, sdkType); } break; case "union": - retVar = fromUnionType(sdkContext, sdkType, externalInfo); + retVar = fromUnionType(sdkContext, sdkType); break; case "utcDateTime": case "offsetDateTime": - retVar = fromSdkDateTimeType(sdkContext, sdkType, externalInfo); + retVar = fromSdkDateTimeType(sdkContext, sdkType); break; case "duration": - retVar = fromSdkDurationType(sdkContext, sdkType, externalInfo); + retVar = fromSdkDurationType(sdkContext, sdkType); break; case "tuple": sdkContext.logger.reportDiagnostic({ @@ -150,7 +140,7 @@ export function fromSdkType( name: "tuple", crossLanguageDefinitionId: "", decorators: sdkType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(sdkType), }; retVar = tupleType; break; @@ -170,12 +160,12 @@ export function fromSdkType( name: "credential", crossLanguageDefinitionId: "", decorators: sdkType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(sdkType), }; retVar = credentialType; break; default: - retVar = fromSdkBuiltInType(sdkContext, sdkType, externalInfo); + retVar = fromSdkBuiltInType(sdkContext, sdkType); break; } @@ -187,7 +177,6 @@ export function fromSdkType( function fromSdkModelType( sdkContext: CSharpEmitterContext, modelType: SdkModelType, - externalInfo?: ExternalTypeInfo, ): InputModelType { // get all unique decorators for the model type from the namespace level and the model level let decorators: DecoratorInfo[] = modelType.decorators; @@ -207,7 +196,7 @@ function fromSdkModelType( summary: modelType.summary, discriminatorValue: modelType.discriminatorValue, decorators: decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(modelType), } as InputModelType; sdkContext.__typeCache.updateSdkTypeReferences(modelType, inputModelType); @@ -289,15 +278,14 @@ function fromSdkModelProperty( return property; } -function fromSdkEnumType(sdkContext: CSharpEmitterContext, enumType: SdkEnumType, externalInfo?: ExternalTypeInfo): InputEnumType { - return createEnumType(sdkContext, enumType, enumType.namespace, externalInfo); +function fromSdkEnumType(sdkContext: CSharpEmitterContext, enumType: SdkEnumType): InputEnumType { + return createEnumType(sdkContext, enumType, enumType.namespace); } function createEnumType( sdkContext: CSharpEmitterContext, sdkType: SdkConstantType | SdkEnumType, namespace: string, - externalInfo?: ExternalTypeInfo, ): InputEnumType { const values: InputEnumValueType[] = []; @@ -322,7 +310,7 @@ function createEnumType( // constantType.usage, TODO - constant type now does not have usage. TCGC will add it later usage: sdkType.kind === "enum" ? sdkType.usage : UsageFlags.None, decorators: sdkType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(sdkType), }; sdkContext.__typeCache.updateSdkTypeReferences(sdkType, inputEnumType); @@ -341,7 +329,6 @@ function createEnumType( function fromSdkDateTimeType( sdkContext: CSharpEmitterContext, dateTimeType: SdkDateTimeType, - externalInfo?: ExternalTypeInfo, ): InputDateTimeType { return { kind: dateTimeType.kind, @@ -351,14 +338,13 @@ function fromSdkDateTimeType( crossLanguageDefinitionId: dateTimeType.crossLanguageDefinitionId, baseType: dateTimeType.baseType ? fromSdkType(sdkContext, dateTimeType.baseType) : undefined, decorators: dateTimeType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(dateTimeType), }; } function fromSdkDurationType( sdkContext: CSharpEmitterContext, durationType: SdkDurationType, - externalInfo?: ExternalTypeInfo, ): InputDurationType { return { kind: durationType.kind, @@ -368,14 +354,13 @@ function fromSdkDurationType( crossLanguageDefinitionId: durationType.crossLanguageDefinitionId, baseType: durationType.baseType ? fromSdkType(sdkContext, durationType.baseType) : undefined, decorators: durationType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(durationType), }; } function fromSdkBuiltInType( sdkContext: CSharpEmitterContext, builtInType: SdkBuiltInType, - externalInfo?: ExternalTypeInfo, ): InputPrimitiveType { return { kind: builtInType.kind, @@ -384,11 +369,11 @@ function fromSdkBuiltInType( crossLanguageDefinitionId: builtInType.crossLanguageDefinitionId, baseType: builtInType.baseType ? fromSdkType(sdkContext, builtInType.baseType) : undefined, decorators: builtInType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(builtInType), }; } -function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType, externalInfo?: ExternalTypeInfo): InputUnionType { +function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType): InputUnionType { const variantTypes: InputType[] = []; for (const value of union.variantTypes) { const variantType = fromSdkType(sdkContext, value); @@ -401,7 +386,7 @@ function fromUnionType(sdkContext: CSharpEmitterContext, union: SdkUnionType, ex variantTypes: variantTypes, namespace: union.namespace, decorators: union.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(union), }; } @@ -458,21 +443,19 @@ function createEnumValueType( function fromSdkDictionaryType( sdkContext: CSharpEmitterContext, dictionaryType: SdkDictionaryType, - externalInfo?: ExternalTypeInfo, ): InputDictionaryType { return { kind: "dict", keyType: fromSdkType(sdkContext, dictionaryType.keyType), valueType: fromSdkType(sdkContext, dictionaryType.valueType), decorators: dictionaryType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(dictionaryType), }; } function fromSdkArrayType( sdkContext: CSharpEmitterContext, arrayType: SdkArrayType, - externalInfo?: ExternalTypeInfo, ): InputArrayType { return { kind: "array", @@ -480,7 +463,7 @@ function fromSdkArrayType( valueType: fromSdkType(sdkContext, arrayType.valueType), crossLanguageDefinitionId: arrayType.crossLanguageDefinitionId, decorators: arrayType.decorators, - external: externalInfo, + external: fromSdkExternalTypeInfo(arrayType), }; } @@ -517,3 +500,21 @@ export function getAllModelDecorators( return Array.from(decoratorMap.values()); } + +/** + * Converts TCGC external type information to InputExternalTypeProperties + * @param sdkType - The SDK type that may have external type information + * @returns InputExternalTypeProperties if the type has external info, undefined otherwise + */ +function fromSdkExternalTypeInfo(sdkType: SdkType): InputExternalTypeProperties | undefined { + const external = (sdkType as any).external; + if (!external) { + return undefined; + } + + return { + identity: external.identity, + package: external.package, + minVersion: external.minVersion, + }; +} diff --git a/packages/http-client-csharp/emitter/src/type/input-type.ts b/packages/http-client-csharp/emitter/src/type/input-type.ts index 0523664d7fa..9c6efde4986 100644 --- a/packages/http-client-csharp/emitter/src/type/input-type.ts +++ b/packages/http-client-csharp/emitter/src/type/input-type.ts @@ -20,7 +20,7 @@ import { RequestLocation } from "./request-location.js"; * External type information for types that map to external library types. * @beta */ -export interface ExternalTypeInfo { +export interface InputExternalTypeProperties { identity: string; package?: string; minVersion?: string; @@ -64,7 +64,7 @@ interface InputTypeBase extends DecoratedType { summary?: string; doc?: string; deprecation?: string; - external?: ExternalTypeInfo; + external?: InputExternalTypeProperties; } export type InputType = @@ -78,8 +78,7 @@ export type InputType = | InputEnumValueType | InputArrayType | InputDictionaryType - | InputNullableType - | InputExternalType; + | InputNullableType; export interface InputPrimitiveType extends InputTypeBase { kind: SdkBuiltInKinds; @@ -285,10 +284,3 @@ export interface InputDictionaryType extends InputTypeBase { keyType: InputType; valueType: InputType; } - -export interface InputExternalType extends InputTypeBase { - kind: "external"; - identity: string; - package?: string; - minVersion?: string; -} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs deleted file mode 100644 index 422c33ed2fd..00000000000 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalType.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.TypeSpec.Generator.Input -{ - /// - /// Represents an external type reference in the input model. - /// - public sealed class InputExternalType : InputType - { - /// - /// Construct a new instance - /// - /// The fully qualified name of the external type. - /// The package that exports the external type. - /// The minimum version of the package. - public InputExternalType(string identity, string? package, string? minVersion) : base("external") - { - Identity = identity; - Package = package; - MinVersion = minVersion; - } - - /// - /// The fully qualified name of the external type. For example, "Azure.Core.Expressions.DataFactoryExpression" - /// - public string Identity { get; } - - /// - /// The package that exports the external type. For example, "Azure.Core.Expressions" - /// - public string? Package { get; } - - /// - /// The minimum version of the package to use for the external type. For example, "1.0.0" - /// - public string? MinVersion { get; } - } -} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeProperties.cs similarity index 84% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeProperties.cs index 781a949cacf..40732b25bb1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/ExternalTypeInfo.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeProperties.cs @@ -6,15 +6,15 @@ namespace Microsoft.TypeSpec.Generator.Input /// /// External type information for types that map to external library types. /// - public sealed class ExternalTypeInfo + public sealed class InputExternalTypeProperties { /// - /// Construct a new instance + /// Construct a new instance /// /// The fully qualified name of the external type. /// The package that exports the external type. /// The minimum version of the package. - public ExternalTypeInfo(string identity, string? package, string? minVersion) + public InputExternalTypeProperties(string identity, string? package, string? minVersion) { Identity = identity; Package = package; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs index a1a1d551629..749f5e2cf76 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs @@ -21,7 +21,7 @@ protected InputType(string name) public string Name { get; internal set; } public IReadOnlyList Decorators { get; internal set; } = new List(); - public ExternalTypeInfo? External { get; internal set; } + public InputExternalTypeProperties? External { get; internal set; } internal InputType GetCollectionEquivalent(InputType inputType) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs index 8f9e1fe7ff7..8c64ea49bb0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs @@ -28,7 +28,7 @@ public static InputArrayType CreateListType(ref Utf8JsonReader reader, string? i string? crossLanguageDefinitionId = null; InputType? valueType = null; IReadOnlyList? decorators = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs index 016a3c49167..1bba73c9c07 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs @@ -29,7 +29,7 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDateTimeType? baseType = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs index 43a5816c4c2..62be3a07d29 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs @@ -28,7 +28,7 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader InputType? keyType = null; InputType? valueType = null; IReadOnlyList? decorators = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs index 7e7ad4cdbd5..3bcbcbf7a6f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs @@ -30,7 +30,7 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDurationType? baseType = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs index af12ead633e..5040bbcec0d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs @@ -60,7 +60,7 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id InputPrimitiveType? valueType = null; IReadOnlyList? values = null; IReadOnlyList? decorators = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs deleted file mode 100644 index 32cf22e3714..00000000000 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeConverter.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Microsoft.TypeSpec.Generator.Input -{ - internal class InputExternalTypeConverter : JsonConverter - { - private readonly TypeSpecReferenceHandler _referenceHandler; - - public InputExternalTypeConverter(TypeSpecReferenceHandler referenceHandler) - { - _referenceHandler = referenceHandler; - } - - public override InputExternalType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalType(ref reader, null, options, _referenceHandler.CurrentResolver); - - public override void Write(Utf8JsonWriter writer, InputExternalType value, JsonSerializerOptions options) - => throw new NotSupportedException("Writing not supported"); - - public static InputExternalType CreateInputExternalType(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) - { - string? identity = null; - string? package = null; - string? minVersion = null; - IReadOnlyList? decorators = null; - - while (reader.TokenType != JsonTokenType.EndObject) - { - var isKnownProperty = reader.TryReadReferenceId(ref id) - || reader.TryReadString("identity", ref identity) - || reader.TryReadString("package", ref package) - || reader.TryReadString("minVersion", ref minVersion) - || reader.TryReadComplexType("decorators", options, ref decorators); - - if (!isKnownProperty) - { - reader.SkipProperty(); - } - } - - identity = identity ?? throw new JsonException("InputExternalType must have identity"); - - var externalType = new InputExternalType(identity, package, minVersion) - { - Decorators = decorators ?? [] - }; - - if (id != null) - { - resolver.AddReference(id, externalType); - } - - return externalType; - } - } -} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypePropertiesConverter.cs similarity index 51% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypePropertiesConverter.cs index 1c5a91627fa..470d96125c6 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/ExternalTypeInfoConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypePropertiesConverter.cs @@ -7,29 +7,29 @@ namespace Microsoft.TypeSpec.Generator.Input { - internal class ExternalTypeInfoConverter : JsonConverter + internal class InputExternalTypePropertiesConverter : JsonConverter { private readonly TypeSpecReferenceHandler _referenceHandler; - public ExternalTypeInfoConverter(TypeSpecReferenceHandler referenceHandler) + public InputExternalTypePropertiesConverter(TypeSpecReferenceHandler referenceHandler) { _referenceHandler = referenceHandler; } - public override ExternalTypeInfo? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override InputExternalTypeProperties? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) { return null; } - return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateExternalTypeInfo(ref reader, null, options, _referenceHandler.CurrentResolver); + return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalTypeProperties(ref reader, null, options, _referenceHandler.CurrentResolver); } - public override void Write(Utf8JsonWriter writer, ExternalTypeInfo value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, InputExternalTypeProperties value, JsonSerializerOptions options) => throw new NotSupportedException("Writing not supported"); - public static ExternalTypeInfo CreateExternalTypeInfo(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) + public static InputExternalTypeProperties CreateInputExternalTypeProperties(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) { string? identity = null; string? package = null; @@ -48,16 +48,16 @@ public static ExternalTypeInfo CreateExternalTypeInfo(ref Utf8JsonReader reader, } } - identity = identity ?? throw new JsonException("ExternalTypeInfo must have identity"); + identity = identity ?? throw new JsonException("InputExternalTypeProperties must have identity"); - var externalTypeInfo = new ExternalTypeInfo(identity, package, minVersion); + var externalTypeProperties = new InputExternalTypeProperties(identity, package, minVersion); if (id != null) { - resolver.AddReference(id, externalTypeInfo); + resolver.AddReference(id, externalTypeProperties); } - return externalTypeInfo; + return externalTypeProperties; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs index 20274b3c976..829315885fb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs @@ -72,7 +72,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string bool modelAsStruct = false; IReadOnlyList? decorators = null; InputSerializationOptions? serializationOptions = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; // read all possible properties and throw away the unknown properties while (reader.TokenType != JsonTokenType.EndObject) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs index 1ef4bb6418c..d860d219be3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs @@ -29,7 +29,7 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, string? encode = null; InputPrimitiveType? baseType = null; IReadOnlyList? decorators = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs index 98fb96a7dd1..eef96ae8571 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputTypeConverter.cs @@ -57,7 +57,6 @@ private static InputType CreateInputType(ref Utf8JsonReader reader, JsonSerializ private const string UtcDateTimeKind = "utcDateTime"; private const string OffsetDateTimeKind = "offsetDateTime"; private const string DurationKind = "duration"; - private const string ExternalKind = "external"; private static InputType CreateDerivedType(ref Utf8JsonReader reader, string? id, string? kind, string? name, JsonSerializerOptions options, ReferenceResolver resolver) => kind switch { @@ -72,7 +71,6 @@ private static InputType CreateInputType(ref Utf8JsonReader reader, JsonSerializ UtcDateTimeKind or OffsetDateTimeKind => InputDateTimeTypeConverter.CreateDateTimeType(ref reader, id, name, options, resolver), DurationKind => InputDurationTypeConverter.CreateDurationType(ref reader, id, name, options, resolver), NullableKind => TypeSpecInputNullableTypeConverter.CreateNullableType(ref reader, id, name, options, resolver), - ExternalKind => InputExternalTypeConverter.CreateInputExternalType(ref reader, id, options, resolver), _ => InputPrimitiveTypeConverter.CreatePrimitiveType(ref reader, id, kind, name, options, resolver), }; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs index 2c717b8ff2e..cf9223230ef 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs @@ -37,7 +37,7 @@ public static InputUnionType CreateInputUnionType(ref Utf8JsonReader reader, str IReadOnlyList? variantTypes = null; IReadOnlyList? decorators = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs index f56a9bfc210..bb8e69a052d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs @@ -26,7 +26,7 @@ public static InputNullableType CreateNullableType(ref Utf8JsonReader reader, st { InputType? valueType = null; IReadOnlyList? decorators = null; - ExternalTypeInfo? external = null; + InputExternalTypeProperties? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index 2ea693751cb..bbb58196d28 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -79,6 +79,12 @@ protected internal TypeFactory() protected virtual CSharpType? CreateCSharpTypeCore(InputType inputType) { + // Check if this type has external type information + if (inputType.External != null) + { + return CreateExternalType(inputType.External); + } + CSharpType? type; switch (inputType) { @@ -125,9 +131,6 @@ protected internal TypeFactory() case InputNullableType nullableType: type = CreateCSharpType(nullableType.Type)?.WithNullable(true); break; - case InputExternalType externalType: - type = CreateExternalType(externalType); - break; default: type = CreatePrimitiveCSharpTypeCore(inputType); break; @@ -233,14 +236,14 @@ protected internal TypeFactory() => EnumProvider.Create(enumType, declaringType); /// - /// Factory method for creating a based on an external type reference . + /// Factory method for creating a based on external type properties. /// - /// The to convert. + /// The to convert. /// A representing the external type, or null if the type cannot be resolved. - private CSharpType? CreateExternalType(InputExternalType externalType) + private CSharpType? CreateExternalType(InputExternalTypeProperties externalProperties) { // Try to create a framework type from the fully qualified name - var frameworkType = CreateFrameworkType(externalType.Identity); + var frameworkType = CreateFrameworkType(externalProperties.Identity); if (frameworkType != null) { return new CSharpType(frameworkType); @@ -250,7 +253,7 @@ protected internal TypeFactory() // Report a diagnostic to inform the user CodeModelGenerator.Instance.Emitter.ReportDiagnostic( "unsupported-external-type", - $"External type '{externalType.Identity}' is not currently supported."); + $"External type '{externalProperties.Identity}' is not currently supported."); return null; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs index b23436d0002..20c1a514984 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs @@ -1163,7 +1163,7 @@ public void ConstantPropertiesAccessibility( public void ExternalTypeModelUsedAsProperty() { // Test a model decorated with alternateType that references System.Uri - var externalType = InputFactory.External("System.Uri"); + var externalType = InputFactory.ExternalUnion("System.Uri", null, null, InputPrimitiveType.String); var modelWithExternal = InputFactory.Model("ExternalModel"); // Create a model that uses the external type as a property @@ -1197,7 +1197,7 @@ public void ExternalTypeModelUsedAsProperty() public void ExternalTypePropertyIsResolved() { // Test a property decorated with alternateType - var externalType = InputFactory.External("System.Net.IPAddress", "System.Net.Primitives", "4.3.0"); + var externalType = InputFactory.ExternalUnion("System.Net.IPAddress", "System.Net.Primitives", "4.3.0", InputPrimitiveType.String); var model = InputFactory.Model( "ModelWithExternalProperty", @@ -1229,7 +1229,7 @@ public void ExternalTypePropertyIsResolved() public void UnsupportedExternalTypeEmitsDiagnostic() { // Test an external type that cannot be resolved (non-framework type) - var externalType = InputFactory.External("Azure.Core.Expressions.DataFactoryExpression"); + var externalType = InputFactory.ExternalUnion("Azure.Core.Expressions.DataFactoryExpression", null, null, InputPrimitiveType.String); var model = InputFactory.Model( "ModelWithUnsupportedExternal", diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs index dce2b4141a2..06b6b169981 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs @@ -629,9 +629,11 @@ public static InputServiceMethodResponse ServiceMethodResponse(InputType? type, return new InputServiceMethodResponse(type, resultSegments); } - public static InputExternalType External(string identity, string? package = null, string? minVersion = null) + public static InputUnionType ExternalUnion(string identity, string? package = null, string? minVersion = null, params InputType[] variantTypes) { - return new InputExternalType(identity, package, minVersion); + var union = new InputUnionType("ExternalUnion", variantTypes.ToList()); + union.External = new InputExternalTypeProperties(identity, package, minVersion); + return union; } private static readonly Dictionary> _childClientsCache = new(); From 87f56a3cd09149c23b110f084f65a8c86775159b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Dec 2025 04:32:43 +0000 Subject: [PATCH 6/9] Rename InputExternalTypeProperties to InputExternalTypeMetadata Applied rename across TypeScript and C# files as requested Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../emitter/src/lib/type-converter.ts | 8 ++++---- .../emitter/src/type/input-type.ts | 4 ++-- ...roperties.cs => InputExternalTypeMetadata.cs} | 6 +++--- .../src/InputTypes/InputType.cs | 2 +- .../Serialization/InputArrayTypeConverter.cs | 2 +- .../Serialization/InputDateTimeTypeConverter.cs | 2 +- .../InputDictionaryTypeConverter.cs | 2 +- .../Serialization/InputDurationTypeConverter.cs | 2 +- .../Serialization/InputEnumTypeConverter.cs | 2 +- ....cs => InputExternalTypeMetadataConverter.cs} | 16 ++++++++-------- .../Serialization/InputModelTypeConverter.cs | 2 +- .../Serialization/InputPrimitiveTypeConverter.cs | 2 +- .../Serialization/InputUnionTypeConverter.cs | 2 +- .../TypeSpecInputNullableTypeConverter.cs | 2 +- .../src/TypeFactory.cs | 4 ++-- .../test/common/InputFactory.cs | 2 +- 16 files changed, 30 insertions(+), 30 deletions(-) rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/{InputExternalTypeProperties.cs => InputExternalTypeMetadata.cs} (84%) rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/{InputExternalTypePropertiesConverter.cs => InputExternalTypeMetadataConverter.cs} (64%) diff --git a/packages/http-client-csharp/emitter/src/lib/type-converter.ts b/packages/http-client-csharp/emitter/src/lib/type-converter.ts index 6f47c003f1d..e99478c8368 100644 --- a/packages/http-client-csharp/emitter/src/lib/type-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/type-converter.ts @@ -37,7 +37,7 @@ import { InputPrimitiveType, InputType, InputUnionType, - InputExternalTypeProperties, + InputExternalTypeMetadata, } from "../type/input-type.js"; import { isReadOnly } from "./utils.js"; @@ -502,11 +502,11 @@ export function getAllModelDecorators( } /** - * Converts TCGC external type information to InputExternalTypeProperties + * Converts TCGC external type information to InputExternalTypeMetadata * @param sdkType - The SDK type that may have external type information - * @returns InputExternalTypeProperties if the type has external info, undefined otherwise + * @returns InputExternalTypeMetadata if the type has external info, undefined otherwise */ -function fromSdkExternalTypeInfo(sdkType: SdkType): InputExternalTypeProperties | undefined { +function fromSdkExternalTypeInfo(sdkType: SdkType): InputExternalTypeMetadata | undefined { const external = (sdkType as any).external; if (!external) { return undefined; diff --git a/packages/http-client-csharp/emitter/src/type/input-type.ts b/packages/http-client-csharp/emitter/src/type/input-type.ts index 9c6efde4986..628aad29e37 100644 --- a/packages/http-client-csharp/emitter/src/type/input-type.ts +++ b/packages/http-client-csharp/emitter/src/type/input-type.ts @@ -20,7 +20,7 @@ import { RequestLocation } from "./request-location.js"; * External type information for types that map to external library types. * @beta */ -export interface InputExternalTypeProperties { +export interface InputExternalTypeMetadata { identity: string; package?: string; minVersion?: string; @@ -64,7 +64,7 @@ interface InputTypeBase extends DecoratedType { summary?: string; doc?: string; deprecation?: string; - external?: InputExternalTypeProperties; + external?: InputExternalTypeMetadata; } export type InputType = diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeProperties.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeMetadata.cs similarity index 84% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeProperties.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeMetadata.cs index 40732b25bb1..37b7fb9955c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeProperties.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputExternalTypeMetadata.cs @@ -6,15 +6,15 @@ namespace Microsoft.TypeSpec.Generator.Input /// /// External type information for types that map to external library types. /// - public sealed class InputExternalTypeProperties + public sealed class InputExternalTypeMetadata { /// - /// Construct a new instance + /// Construct a new instance /// /// The fully qualified name of the external type. /// The package that exports the external type. /// The minimum version of the package. - public InputExternalTypeProperties(string identity, string? package, string? minVersion) + public InputExternalTypeMetadata(string identity, string? package, string? minVersion) { Identity = identity; Package = package; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs index 749f5e2cf76..f29410ac780 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/InputType.cs @@ -21,7 +21,7 @@ protected InputType(string name) public string Name { get; internal set; } public IReadOnlyList Decorators { get; internal set; } = new List(); - public InputExternalTypeProperties? External { get; internal set; } + public InputExternalTypeMetadata? External { get; internal set; } internal InputType GetCollectionEquivalent(InputType inputType) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs index 8c64ea49bb0..c7b2eaf884f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputArrayTypeConverter.cs @@ -28,7 +28,7 @@ public static InputArrayType CreateListType(ref Utf8JsonReader reader, string? i string? crossLanguageDefinitionId = null; InputType? valueType = null; IReadOnlyList? decorators = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs index 1bba73c9c07..9cec784fcff 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDateTimeTypeConverter.cs @@ -29,7 +29,7 @@ public static InputDateTimeType CreateDateTimeType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDateTimeType? baseType = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs index 62be3a07d29..429cb5f396f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDictionaryTypeConverter.cs @@ -28,7 +28,7 @@ public static InputDictionaryType CreateDictionaryType(ref Utf8JsonReader reader InputType? keyType = null; InputType? valueType = null; IReadOnlyList? decorators = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs index 3bcbcbf7a6f..3107ddc9f0c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputDurationTypeConverter.cs @@ -30,7 +30,7 @@ public static InputDurationType CreateDurationType(ref Utf8JsonReader reader, st InputPrimitiveType? wireType = null; IReadOnlyList? decorators = null; InputDurationType? baseType = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs index 5040bbcec0d..028ee85c25f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputEnumTypeConverter.cs @@ -60,7 +60,7 @@ public static InputEnumType CreateEnumType(ref Utf8JsonReader reader, string? id InputPrimitiveType? valueType = null; IReadOnlyList? values = null; IReadOnlyList? decorators = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypePropertiesConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs similarity index 64% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypePropertiesConverter.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs index 470d96125c6..e31ab43d48d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypePropertiesConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputExternalTypeMetadataConverter.cs @@ -7,29 +7,29 @@ namespace Microsoft.TypeSpec.Generator.Input { - internal class InputExternalTypePropertiesConverter : JsonConverter + internal class InputExternalTypeMetadataConverter : JsonConverter { private readonly TypeSpecReferenceHandler _referenceHandler; - public InputExternalTypePropertiesConverter(TypeSpecReferenceHandler referenceHandler) + public InputExternalTypeMetadataConverter(TypeSpecReferenceHandler referenceHandler) { _referenceHandler = referenceHandler; } - public override InputExternalTypeProperties? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override InputExternalTypeMetadata? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) { return null; } - return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalTypeProperties(ref reader, null, options, _referenceHandler.CurrentResolver); + return reader.ReadReferenceAndResolve(_referenceHandler.CurrentResolver) ?? CreateInputExternalTypeMetadata(ref reader, null, options, _referenceHandler.CurrentResolver); } - public override void Write(Utf8JsonWriter writer, InputExternalTypeProperties value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, InputExternalTypeMetadata value, JsonSerializerOptions options) => throw new NotSupportedException("Writing not supported"); - public static InputExternalTypeProperties CreateInputExternalTypeProperties(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) + public static InputExternalTypeMetadata CreateInputExternalTypeMetadata(ref Utf8JsonReader reader, string? id, JsonSerializerOptions options, ReferenceResolver resolver) { string? identity = null; string? package = null; @@ -48,9 +48,9 @@ public static InputExternalTypeProperties CreateInputExternalTypeProperties(ref } } - identity = identity ?? throw new JsonException("InputExternalTypeProperties must have identity"); + identity = identity ?? throw new JsonException("InputExternalTypeMetadata must have identity"); - var externalTypeProperties = new InputExternalTypeProperties(identity, package, minVersion); + var externalTypeProperties = new InputExternalTypeMetadata(identity, package, minVersion); if (id != null) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs index 829315885fb..32ae2cc5aee 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputModelTypeConverter.cs @@ -72,7 +72,7 @@ internal static InputModelType CreateModelType(ref Utf8JsonReader reader, string bool modelAsStruct = false; IReadOnlyList? decorators = null; InputSerializationOptions? serializationOptions = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; // read all possible properties and throw away the unknown properties while (reader.TokenType != JsonTokenType.EndObject) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs index d860d219be3..00f9ec2c179 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputPrimitiveTypeConverter.cs @@ -29,7 +29,7 @@ public static InputPrimitiveType CreatePrimitiveType(ref Utf8JsonReader reader, string? encode = null; InputPrimitiveType? baseType = null; IReadOnlyList? decorators = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs index cf9223230ef..23c8cb8b31a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/InputUnionTypeConverter.cs @@ -37,7 +37,7 @@ public static InputUnionType CreateInputUnionType(ref Utf8JsonReader reader, str IReadOnlyList? variantTypes = null; IReadOnlyList? decorators = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadString("name", ref name) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs index bb8e69a052d..55c6e6d2d1a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/TypeSpecInputNullableTypeConverter.cs @@ -26,7 +26,7 @@ public static InputNullableType CreateNullableType(ref Utf8JsonReader reader, st { InputType? valueType = null; IReadOnlyList? decorators = null; - InputExternalTypeProperties? external = null; + InputExternalTypeMetadata? external = null; while (reader.TokenType != JsonTokenType.EndObject) { var isKnownProperty = reader.TryReadReferenceId(ref id) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index bbb58196d28..705a331086a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -238,9 +238,9 @@ protected internal TypeFactory() /// /// Factory method for creating a based on external type properties. /// - /// The to convert. + /// The to convert. /// A representing the external type, or null if the type cannot be resolved. - private CSharpType? CreateExternalType(InputExternalTypeProperties externalProperties) + private CSharpType? CreateExternalType(InputExternalTypeMetadata externalProperties) { // Try to create a framework type from the fully qualified name var frameworkType = CreateFrameworkType(externalProperties.Identity); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs index 06b6b169981..166268448e9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs @@ -632,7 +632,7 @@ public static InputServiceMethodResponse ServiceMethodResponse(InputType? type, public static InputUnionType ExternalUnion(string identity, string? package = null, string? minVersion = null, params InputType[] variantTypes) { var union = new InputUnionType("ExternalUnion", variantTypes.ToList()); - union.External = new InputExternalTypeProperties(identity, package, minVersion); + union.External = new InputExternalTypeMetadata(identity, package, minVersion); return union; } From 6ab041fc1df70fe9e1d20699b3d61860517c06c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 01:54:28 +0000 Subject: [PATCH 7/9] Replace ExternalUnion with optional parameter in Union method - Removed ExternalUnion helper method - Added optional InputExternalTypeMetadata parameter to Union method - Updated all test usages to use Union method with external parameter Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../ModelProviders/ModelProviderTests.cs | 15 ++++++++++++--- .../test/common/InputFactory.cs | 16 +++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs index 20c1a514984..a3f6f3c0f00 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs @@ -1163,7 +1163,10 @@ public void ConstantPropertiesAccessibility( public void ExternalTypeModelUsedAsProperty() { // Test a model decorated with alternateType that references System.Uri - var externalType = InputFactory.ExternalUnion("System.Uri", null, null, InputPrimitiveType.String); + var externalType = InputFactory.Union( + [InputPrimitiveType.String], + "ExternalUnion", + new InputExternalTypeMetadata("System.Uri", null, null)); var modelWithExternal = InputFactory.Model("ExternalModel"); // Create a model that uses the external type as a property @@ -1197,7 +1200,10 @@ public void ExternalTypeModelUsedAsProperty() public void ExternalTypePropertyIsResolved() { // Test a property decorated with alternateType - var externalType = InputFactory.ExternalUnion("System.Net.IPAddress", "System.Net.Primitives", "4.3.0", InputPrimitiveType.String); + var externalType = InputFactory.Union( + [InputPrimitiveType.String], + "ExternalUnion", + new InputExternalTypeMetadata("System.Net.IPAddress", "System.Net.Primitives", "4.3.0")); var model = InputFactory.Model( "ModelWithExternalProperty", @@ -1229,7 +1235,10 @@ public void ExternalTypePropertyIsResolved() public void UnsupportedExternalTypeEmitsDiagnostic() { // Test an external type that cannot be resolved (non-framework type) - var externalType = InputFactory.ExternalUnion("Azure.Core.Expressions.DataFactoryExpression", null, null, InputPrimitiveType.String); + var externalType = InputFactory.Union( + [InputPrimitiveType.String], + "ExternalUnion", + new InputExternalTypeMetadata("Azure.Core.Expressions.DataFactoryExpression", null, null)); var model = InputFactory.Model( "ModelWithUnsupportedExternal", diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs index 166268448e9..adb80a053ba 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs @@ -493,9 +493,14 @@ public static InputType Dictionary(InputType valueType, InputType? keyType = nul return new InputDictionaryType("dictionary", keyType ?? InputPrimitiveType.String, valueType); } - public static InputType Union(IList types, string name = "union") + public static InputType Union(IList types, string name = "union", InputExternalTypeMetadata? external = null) { - return new InputUnionType(name, [.. types]); + var union = new InputUnionType(name, [.. types]); + if (external != null) + { + union.External = external; + } + return union; } public static InputBasicServiceMethod BasicServiceMethod( @@ -629,13 +634,6 @@ public static InputServiceMethodResponse ServiceMethodResponse(InputType? type, return new InputServiceMethodResponse(type, resultSegments); } - public static InputUnionType ExternalUnion(string identity, string? package = null, string? minVersion = null, params InputType[] variantTypes) - { - var union = new InputUnionType("ExternalUnion", variantTypes.ToList()); - union.External = new InputExternalTypeMetadata(identity, package, minVersion); - return union; - } - private static readonly Dictionary> _childClientsCache = new(); public static InputClient Client(string name, string clientNamespace = "Sample", string? doc = null, IEnumerable? methods = null, IEnumerable? parameters = null, InputClient? parent = null, string? crossLanguageDefinitionId = null, IEnumerable? apiVersions = null, InputClientInitializedBy initializedBy = InputClientInitializedBy.Default) From 8f072bdde1e7e6dbb693d64d47daf5d889528920 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:03:46 +0000 Subject: [PATCH 8/9] Add optional external parameter to all factory methods and deserialization tests - Added InputExternalTypeMetadata parameter to Array, Dictionary, Model, and Enum factory methods - Added 5 comprehensive tests for External property deserialization covering Union, Model, Array, Dictionary, and Enum types Co-authored-by: JoshLove-msft <54595583+JoshLove-msft@users.noreply.github.com> --- .../test/TypeSpecInputConverterTests.cs | 185 ++++++++++++++++++ .../test/common/InputFactory.cs | 62 ++++-- 2 files changed, 232 insertions(+), 15 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs index 1a2c31b7cba..a73ae78abc3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/test/TypeSpecInputConverterTests.cs @@ -436,5 +436,190 @@ public void LoadsClientWithSubclientInitializedBy() Assert.AreEqual("ParentClient", subClient.Parent!.Name, "SubClient's parent should be ParentClient"); Assert.AreEqual(0, subClient.Children.Count, "SubClient should have no children"); } + + [Test] + public void DeserializeUnionWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""union"", + ""name"": ""TestUnion"", + ""variantTypes"": [ + { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" } + ], + ""external"": { + ""identity"": ""Azure.Core.Expressions.DataFactoryElement"", + ""package"": ""Azure.Core.Expressions"", + ""minVersion"": ""1.0.0"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputUnionTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var union = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(union); + Assert.IsNotNull(union!.External); + Assert.AreEqual("Azure.Core.Expressions.DataFactoryElement", union.External!.Identity); + Assert.AreEqual("Azure.Core.Expressions", union.External.Package); + Assert.AreEqual("1.0.0", union.External.MinVersion); + Assert.AreEqual(1, union.VariantTypes.Count); + } + + [Test] + public void DeserializeModelWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""model"", + ""name"": ""TestModel"", + ""namespace"": ""Test.Models"", + ""crossLanguageDefinitionId"": ""Test.Models.TestModel"", + ""usage"": ""None"", + ""properties"": [], + ""external"": { + ""identity"": ""System.Text.Json.JsonElement"", + ""package"": ""System.Text.Json"", + ""minVersion"": ""8.0.0"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputModelTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var model = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(model); + Assert.IsNotNull(model!.External); + Assert.AreEqual("System.Text.Json.JsonElement", model.External!.Identity); + Assert.AreEqual("System.Text.Json", model.External.Package); + Assert.AreEqual("8.0.0", model.External.MinVersion); + } + + [Test] + public void DeserializeArrayWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""array"", + ""name"": ""TestArray"", + ""crossLanguageDefinitionId"": ""TestArray"", + ""valueType"": { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""external"": { + ""identity"": ""System.Collections.Generic.IList"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputArrayTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var array = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(array); + Assert.IsNotNull(array!.External); + Assert.AreEqual("System.Collections.Generic.IList", array.External!.Identity); + Assert.IsNull(array.External.Package); + Assert.IsNull(array.External.MinVersion); + } + + [Test] + public void DeserializeDictionaryWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""dict"", + ""keyType"": { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""valueType"": { ""$id"": ""3"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""external"": { + ""identity"": ""System.Collections.Generic.IDictionary"", + ""package"": ""System.Collections"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputDictionaryTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var dictionary = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(dictionary); + Assert.IsNotNull(dictionary!.External); + Assert.AreEqual("System.Collections.Generic.IDictionary", dictionary.External!.Identity); + Assert.AreEqual("System.Collections", dictionary.External.Package); + Assert.IsNull(dictionary.External.MinVersion); + } + + [Test] + public void DeserializeEnumWithExternalMetadata() + { + var json = @"{ + ""$id"": ""1"", + ""kind"": ""enum"", + ""name"": ""TestEnum"", + ""namespace"": ""Test.Models"", + ""crossLanguageDefinitionId"": ""Test.Models.TestEnum"", + ""valueType"": { ""$id"": ""2"", ""kind"": ""string"", ""name"": ""string"", ""crossLanguageDefinitionId"": ""TypeSpec.string"" }, + ""values"": [], + ""isFixed"": true, + ""external"": { + ""identity"": ""System.DayOfWeek"" + } + }"; + + var referenceHandler = new TypeSpecReferenceHandler(); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + Converters = + { + new InputTypeConverter(referenceHandler), + new InputEnumTypeConverter(referenceHandler), + new InputPrimitiveTypeConverter(referenceHandler), + new InputExternalTypeMetadataConverter(referenceHandler) + } + }; + + var enumType = JsonSerializer.Deserialize(json, options); + Assert.IsNotNull(enumType); + Assert.IsNotNull(enumType!.External); + Assert.AreEqual("System.DayOfWeek", enumType.External!.Identity); + Assert.IsNull(enumType.External.Package); + Assert.IsNull(enumType.External.MinVersion); + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs index adb80a053ba..3492ce53eed 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/common/InputFactory.cs @@ -98,7 +98,8 @@ public static InputEnumType StringEnum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -108,7 +109,8 @@ public static InputEnumType StringEnum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -124,7 +126,8 @@ public static InputEnumType Int32Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -134,7 +137,8 @@ public static InputEnumType Int32Enum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -150,7 +154,8 @@ public static InputEnumType Float32Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -160,7 +165,8 @@ public static InputEnumType Float32Enum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -176,7 +182,8 @@ public static InputEnumType Float64Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Input | InputModelTypeUsage.Output, bool isExtensible = false, - string clientNamespace = "Sample.Models") + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) { var enumValues = new List(); var enumType = Enum( @@ -186,7 +193,8 @@ public static InputEnumType Float64Enum( access: access, usage: usage, isExtensible: isExtensible, - clientNamespace: clientNamespace); + clientNamespace: clientNamespace, + external: external); foreach (var (valueName, value) in values) { @@ -203,8 +211,10 @@ private static InputEnumType Enum( string access = "public", InputModelTypeUsage usage = InputModelTypeUsage.Output | InputModelTypeUsage.Input, bool isExtensible = false, - string clientNamespace = "Sample.Models") - => new InputEnumType( + string clientNamespace = "Sample.Models", + InputExternalTypeMetadata? external = null) + { + var enumType = new InputEnumType( name, clientNamespace, name, @@ -216,6 +226,12 @@ private static InputEnumType Enum( underlyingType, values, isExtensible); + if (external != null) + { + enumType.External = external; + } + return enumType; + } public static InputModelProperty Property( string name, @@ -449,7 +465,8 @@ public static InputModelType Model( IDictionary? discriminatedModels = null, IEnumerable? derivedModels = null, InputModelProperty? discriminatorProperty = null, - bool isDynamicModel = false) + bool isDynamicModel = false, + InputExternalTypeMetadata? external = null) { IEnumerable propertiesList = properties ?? [Property("StringProperty", InputPrimitiveType.String)]; @@ -480,17 +497,32 @@ discriminatedModels is null _addDerivedModelMethod.Invoke(baseModel, new object[] { model }); } + if (external != null) + { + model.External = external; + } + return model; } - public static InputType Array(InputType elementType) + public static InputType Array(InputType elementType, InputExternalTypeMetadata? external = null) { - return new InputArrayType("list", "list", elementType); + var array = new InputArrayType("list", "list", elementType); + if (external != null) + { + array.External = external; + } + return array; } - public static InputType Dictionary(InputType valueType, InputType? keyType = null) + public static InputType Dictionary(InputType valueType, InputType? keyType = null, InputExternalTypeMetadata? external = null) { - return new InputDictionaryType("dictionary", keyType ?? InputPrimitiveType.String, valueType); + var dictionary = new InputDictionaryType("dictionary", keyType ?? InputPrimitiveType.String, valueType); + if (external != null) + { + dictionary.External = external; + } + return dictionary; } public static InputType Union(IList types, string name = "union", InputExternalTypeMetadata? external = null) From 02c35df44b320ca0395cda6abe499cee58ec184d Mon Sep 17 00:00:00 2001 From: jolov Date: Mon, 8 Dec 2025 09:25:11 -0800 Subject: [PATCH 9/9] format --- .../http-client-csharp/emitter/src/lib/type-converter.ts | 4 ++-- .../emitter/test/Unit/type-converter.test.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/http-client-csharp/emitter/src/lib/type-converter.ts b/packages/http-client-csharp/emitter/src/lib/type-converter.ts index e99478c8368..f6b31db5578 100644 --- a/packages/http-client-csharp/emitter/src/lib/type-converter.ts +++ b/packages/http-client-csharp/emitter/src/lib/type-converter.ts @@ -29,6 +29,7 @@ import { InputDurationType, InputEnumType, InputEnumValueType, + InputExternalTypeMetadata, InputLiteralType, InputModelProperty, InputModelType, @@ -37,7 +38,6 @@ import { InputPrimitiveType, InputType, InputUnionType, - InputExternalTypeMetadata, } from "../type/input-type.js"; import { isReadOnly } from "./utils.js"; @@ -511,7 +511,7 @@ function fromSdkExternalTypeInfo(sdkType: SdkType): InputExternalTypeMetadata | if (!external) { return undefined; } - + return { identity: external.identity, package: external.package, diff --git a/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts b/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts index 931a5fdc58f..081708c903f 100644 --- a/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts +++ b/packages/http-client-csharp/emitter/test/Unit/type-converter.test.ts @@ -130,7 +130,10 @@ describe("External types", () => { // The type should remain a union but with external info strictEqual(prop.type.kind, "union"); ok((prop.type as any).external, "Type should have external info"); - strictEqual((prop.type as any).external.identity, "Azure.Core.Expressions.DataFactoryExpression"); + strictEqual( + (prop.type as any).external.identity, + "Azure.Core.Expressions.DataFactoryExpression", + ); strictEqual((prop.type as any).external.package, "Azure.Core.Expressions"); strictEqual((prop.type as any).external.minVersion, "1.0.0"); // Verify union variants are preserved