From eb52af37d418942e807adb4c3976b17b56824ed6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:00:04 +0000 Subject: [PATCH 1/9] Initial plan From 1ac17bd2e07217282b08ee7adedf6ec86fac7632 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:06:59 +0000 Subject: [PATCH 2/9] Add comprehensive backward compatibility documentation Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 300 ++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 packages/http-client-csharp/generator/docs/backward-compatibility.md diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md new file mode 100644 index 00000000000..88f9d0f5dd2 --- /dev/null +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -0,0 +1,300 @@ +# Backward Compatibility Support + +## Table of Contents + +- [Overview](#overview) +- [How It Works](#how-it-works) +- [Supported Scenarios](#supported-scenarios) + - [Model Factory Methods](#model-factory-methods) + - [Model Properties](#model-properties) + - [API Version Enum](#api-version-enum) +- [Technical Implementation](#technical-implementation) +- [Best Practices](#best-practices) + +## Overview + +The TypeSpec C# generator supports backward compatibility (back-compat) to ensure that existing client code continues to work when the service API evolves. This is achieved by comparing the current generated code against a previous contract (assembly) and automatically generating compatibility shims where needed. + +The backward compatibility system uses the `LastContractView` mechanism to access information about previously generated types, methods, and properties from the last released version of the library. + +## How It Works + +When generating code, the generator can optionally receive a compiled assembly from the previous version of the library (the "last contract"). The generator: + +1. Analyzes the current TypeSpec specification and generates types based on the current API +2. Compares the generated types against the types in the last contract +3. Automatically generates compatibility methods, properties, or enum members where differences are detected +4. Marks compatibility members with `[EditorBrowsable(EditorBrowsableState.Never)]` to hide them from IntelliSense while keeping them available for existing code + +## Supported Scenarios + +### Model Factory Methods + +Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator maintains backward compatibility for these methods across API changes. + +#### Scenario 1: New Model Property Added + +**Description:** When a new property is added to a model, the generator creates a backward-compatible factory method overload that excludes the new parameter. + +**Example:** + +Previous version had a model with three properties: +```csharp +public static PublicModel1 PublicModel1( + string stringProp = default, + Thing modelProp = default, + IEnumerable listProp = default) +``` + +Current version adds a new property (`dictProp`): +```csharp +public static PublicModel1 PublicModel1( + string stringProp = default, + Thing modelProp = default, + IEnumerable listProp = default, + IDictionary dictProp = default) +``` + +**Generated Compatibility Method:** +```csharp +[EditorBrowsable(EditorBrowsableState.Never)] +public static PublicModel1 PublicModel1( + string stringProp, + Thing modelProp, + IEnumerable listProp) +{ + return PublicModel1(stringProp, modelProp, listProp, dictProp: default); +} +``` + +**Key Points:** +- The old method signature is preserved +- It delegates to the new method with default value for the new parameter +- Parameters in the compatibility method have no default values to avoid ambiguous call sites +- The method is marked with `[EditorBrowsable(EditorBrowsableState.Never)]` to hide it from IntelliSense + +#### Scenario 2: Parameter Ordering Changed + +**Description:** When only the parameter ordering changes in a factory method (same parameters, different order), the generator replaces the current method with the previous method signature. + +**Example:** + +Previous version: +```csharp +public static PublicModel1 PublicModel1( + Thing modelProp = default, + string stringProp = default, + IEnumerable listProp = default, + IDictionary dictProp = default) +``` + +Current version would generate different ordering: +```csharp +public static PublicModel1 PublicModel1( + string stringProp = default, + Thing modelProp = default, + IEnumerable listProp = default, + IDictionary dictProp = default) +``` + +**Result:** The generator keeps the previous parameter ordering to maintain compatibility. + +#### Scenario 3: Model Factory Method Renamed + +**Description:** When a model or factory method is renamed, the generator creates a compatibility method with the old name that instantiates the new model type. + +**Example:** + +Previous version: +```csharp +public static PublicModel1 PublicModel1OldName(string stringProp = default) +``` + +Current version: +```csharp +public static PublicModel1 PublicModel1( + string stringProp = default, + Thing modelProp = default, + IEnumerable listProp = default, + IDictionary dictProp = default) +``` + +**Generated Compatibility Method:** +```csharp +[EditorBrowsable(EditorBrowsableState.Never)] +public static PublicModel1 PublicModel1OldName(string stringProp) +{ + return new PublicModel1(stringProp, default, default, default); +} +``` + +**Key Points:** +- The old method name is preserved +- The method creates an instance of the new model type +- Missing parameters are filled with default values + +### Model Properties + +The generator maintains backward compatibility for model property types, particularly for collection types. + +#### Scenario: Collection Property Type Changed + +**Description:** When a property type changes from a read-only collection to a read-write collection (or vice versa), the generator preserves the previous property type to avoid breaking changes. + +**Example:** + +Previous version: +```csharp +public IReadOnlyList Items { get; } +``` + +Current TypeSpec would generate: +```csharp +public IList Items { get; set; } +``` + +**Result:** The generator detects the type mismatch and preserves the previous type: +```csharp +public IReadOnlyList Items { get; } +``` + +**Implementation Details:** +- The generator compares property types against the `LastContractView` +- For read-write lists and dictionaries, if the previous type was different, the previous type is retained +- A diagnostic message is logged: `"Changed property {ModelName}.{PropertyName} type to {LastContractType} to match last contract."` + +### API Version Enum + +Service version enums maintain backward compatibility by preserving version values from previous releases. + +#### Scenario: API Version Removed or Changed + +**Description:** When API versions are removed or changed in the TypeSpec, the generator preserves previous version enum members to prevent breaking existing code that references them. + +**Example:** + +Previous version had enum members: +```csharp +public enum ServiceVersion +{ + V2021_10_01 = 1, + V2022_01_01 = 2, + V2022_06_01 = 3, +} +``` + +Current TypeSpec removes `V2021_10_01` and adds `V2023_01_01`: +```csharp +public enum ServiceVersion +{ + V2022_01_01 = 1, + V2022_06_01 = 2, + V2023_01_01 = 3, +} +``` + +**Generated Result:** +```csharp +public enum ServiceVersion +{ + V2021_10_01 = 1, // Preserved from previous version + V2022_01_01 = 2, + V2022_06_01 = 3, + V2023_01_01 = 4, +} +``` + +**Key Points:** +- Previous enum members are preserved even if removed from TypeSpec +- Enum values are re-indexed to maintain sequential ordering +- Version format and separator are detected from current versions and applied to previous versions + +## Technical Implementation + +### LastContractView Property + +The `LastContractView` property is available on `TypeProvider` and provides access to the type definition from the previous contract: + +```csharp +public TypeProvider? LastContractView { get; } +``` + +**Key Members Accessed:** +- `LastContractView.Methods` - Previous method signatures (used in ModelFactoryProvider) +- `LastContractView.Properties` - Previous property definitions (used in ModelProvider) +- `LastContractView.Fields` - Previous field definitions (used in ApiVersionEnumProvider) + +### Implementation Locations + +1. **ModelFactoryProvider.cs** + - Method: `BuildMethodsForBackCompatibility()` + - Compares current and previous factory method signatures + - Generates compatibility methods for missing overloads + - Location: `/src/Providers/ModelFactoryProvider.cs` (lines 112-186) + +2. **ModelProvider.cs** + - Method: `BuildProperties()` + - Compares property types using `LastContractPropertiesMap` + - Preserves previous collection types when changed + - Location: `/src/Providers/ModelProvider.cs` (lines 446-456) + +3. **ApiVersionEnumProvider.cs** + - Method: `BuildApiVersionEnumValuesForBackwardCompatibility()` + - Preserves enum members from previous versions + - Re-indexes values to maintain sequential ordering + - Location: `/src/Providers/ApiVersionEnumProvider.cs` (lines 98-145) + +### SourceInputModel + +The `SourceInputModel` class provides the mechanism to query types from the last contract: + +```csharp +public TypeProvider? FindForTypeInLastContract( + string ns, + string name, + string? declaringTypeName = null) +``` + +This method searches the compiled last contract assembly for type symbols matching the specified namespace and name. + +## Best Practices + +### When Using Backward Compatibility + +1. **Always provide the last contract assembly** when generating code for a new version of your library to ensure backward compatibility is maintained. + +2. **Review compatibility methods** generated by the system to ensure they behave as expected. Check the generated code for methods marked with `[EditorBrowsable(EditorBrowsableState.Never)]`. + +3. **Test with existing code** that uses previous API versions to validate that compatibility is maintained. + +4. **Monitor diagnostics** - The generator logs informational messages when it makes changes for backward compatibility: + - `"Changed property {Name}.{PropertyName} type to {Type} to match last contract."` + - `"Unable to create a backward compatible model factory method for {MethodName}."` + +### Limitations + +1. **Structural Changes:** Major structural changes (e.g., changing from class to struct) cannot be automatically handled and may require manual intervention. + +2. **Breaking Changes:** Some changes are inherently breaking and cannot be automatically mitigated: + - Changing method return types + - Removing public types + - Changing property types to incompatible types (non-collection changes) + +3. **Internal Types:** Backward compatibility only applies to public types and members. Internal types are excluded from compatibility processing. + +4. **Custom Code:** If you have customized a type or method, the backward compatibility system may not be able to generate appropriate compatibility shims. Manual adjustments may be needed. + +### Testing + +The generator includes comprehensive tests for backward compatibility scenarios: + +- **Test Location:** `/test/Providers/ModelFactories/ModelFactoryProviderTests.cs` +- **Test Methods:** + - `BackCompatibility_NewModelPropertyAdded` - Tests factory methods when properties are added + - `BackCompatibility_OnlyParamOrderingChanged` - Tests parameter ordering preservation + - `BackCompatibility_NoCurrentOverloadFound` - Tests renamed method handling + +Run these tests to validate backward compatibility behavior: +```bash +dotnet test --filter "FullyQualifiedName~ModelFactoryProviderTests.BackCompatibility" +``` From bd6df7dee9aa119d0d136b5f9465cc96e4a800a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:10:58 +0000 Subject: [PATCH 3/9] Complete backward compatibility documentation Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../http-client-csharp/generator/docs/backward-compatibility.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index 88f9d0f5dd2..75ab54a1e48 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -296,5 +296,6 @@ The generator includes comprehensive tests for backward compatibility scenarios: Run these tests to validate backward compatibility behavior: ```bash +# From the generator root directory dotnet test --filter "FullyQualifiedName~ModelFactoryProviderTests.BackCompatibility" ``` From eb56853265a267c6ffc071581b9a2aa8f363e062 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:22:45 +0000 Subject: [PATCH 4/9] Address PR feedback: simplify documentation and fix inaccuracies Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 134 +----------------- 1 file changed, 3 insertions(+), 131 deletions(-) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index 75ab54a1e48..731bc9254a2 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -8,8 +8,6 @@ - [Model Factory Methods](#model-factory-methods) - [Model Properties](#model-properties) - [API Version Enum](#api-version-enum) -- [Technical Implementation](#technical-implementation) -- [Best Practices](#best-practices) ## Overview @@ -24,13 +22,12 @@ When generating code, the generator can optionally receive a compiled assembly f 1. Analyzes the current TypeSpec specification and generates types based on the current API 2. Compares the generated types against the types in the last contract 3. Automatically generates compatibility methods, properties, or enum members where differences are detected -4. Marks compatibility members with `[EditorBrowsable(EditorBrowsableState.Never)]` to hide them from IntelliSense while keeping them available for existing code ## Supported Scenarios ### Model Factory Methods -Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator maintains backward compatibility for these methods across API changes. +Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator attempts to maintains backward compatibility for these methods across API changes. #### Scenario 1: New Model Property Added @@ -99,47 +96,13 @@ public static PublicModel1 PublicModel1( **Result:** The generator keeps the previous parameter ordering to maintain compatibility. -#### Scenario 3: Model Factory Method Renamed - -**Description:** When a model or factory method is renamed, the generator creates a compatibility method with the old name that instantiates the new model type. - -**Example:** - -Previous version: -```csharp -public static PublicModel1 PublicModel1OldName(string stringProp = default) -``` - -Current version: -```csharp -public static PublicModel1 PublicModel1( - string stringProp = default, - Thing modelProp = default, - IEnumerable listProp = default, - IDictionary dictProp = default) -``` - -**Generated Compatibility Method:** -```csharp -[EditorBrowsable(EditorBrowsableState.Never)] -public static PublicModel1 PublicModel1OldName(string stringProp) -{ - return new PublicModel1(stringProp, default, default, default); -} -``` - -**Key Points:** -- The old method name is preserved -- The method creates an instance of the new model type -- Missing parameters are filled with default values - ### Model Properties -The generator maintains backward compatibility for model property types, particularly for collection types. +The generator attempts to maintain backward compatibility for model property types, particularly for collection types. #### Scenario: Collection Property Type Changed -**Description:** When a property type changes from a read-only collection to a read-write collection (or vice versa), the generator preserves the previous property type to avoid breaking changes. +**Description:** When a property type changes from a read-only collection to a read-write collection (or vice versa), the generator attempts to preserve the previous property type to avoid breaking changes. **Example:** @@ -208,94 +171,3 @@ public enum ServiceVersion - Previous enum members are preserved even if removed from TypeSpec - Enum values are re-indexed to maintain sequential ordering - Version format and separator are detected from current versions and applied to previous versions - -## Technical Implementation - -### LastContractView Property - -The `LastContractView` property is available on `TypeProvider` and provides access to the type definition from the previous contract: - -```csharp -public TypeProvider? LastContractView { get; } -``` - -**Key Members Accessed:** -- `LastContractView.Methods` - Previous method signatures (used in ModelFactoryProvider) -- `LastContractView.Properties` - Previous property definitions (used in ModelProvider) -- `LastContractView.Fields` - Previous field definitions (used in ApiVersionEnumProvider) - -### Implementation Locations - -1. **ModelFactoryProvider.cs** - - Method: `BuildMethodsForBackCompatibility()` - - Compares current and previous factory method signatures - - Generates compatibility methods for missing overloads - - Location: `/src/Providers/ModelFactoryProvider.cs` (lines 112-186) - -2. **ModelProvider.cs** - - Method: `BuildProperties()` - - Compares property types using `LastContractPropertiesMap` - - Preserves previous collection types when changed - - Location: `/src/Providers/ModelProvider.cs` (lines 446-456) - -3. **ApiVersionEnumProvider.cs** - - Method: `BuildApiVersionEnumValuesForBackwardCompatibility()` - - Preserves enum members from previous versions - - Re-indexes values to maintain sequential ordering - - Location: `/src/Providers/ApiVersionEnumProvider.cs` (lines 98-145) - -### SourceInputModel - -The `SourceInputModel` class provides the mechanism to query types from the last contract: - -```csharp -public TypeProvider? FindForTypeInLastContract( - string ns, - string name, - string? declaringTypeName = null) -``` - -This method searches the compiled last contract assembly for type symbols matching the specified namespace and name. - -## Best Practices - -### When Using Backward Compatibility - -1. **Always provide the last contract assembly** when generating code for a new version of your library to ensure backward compatibility is maintained. - -2. **Review compatibility methods** generated by the system to ensure they behave as expected. Check the generated code for methods marked with `[EditorBrowsable(EditorBrowsableState.Never)]`. - -3. **Test with existing code** that uses previous API versions to validate that compatibility is maintained. - -4. **Monitor diagnostics** - The generator logs informational messages when it makes changes for backward compatibility: - - `"Changed property {Name}.{PropertyName} type to {Type} to match last contract."` - - `"Unable to create a backward compatible model factory method for {MethodName}."` - -### Limitations - -1. **Structural Changes:** Major structural changes (e.g., changing from class to struct) cannot be automatically handled and may require manual intervention. - -2. **Breaking Changes:** Some changes are inherently breaking and cannot be automatically mitigated: - - Changing method return types - - Removing public types - - Changing property types to incompatible types (non-collection changes) - -3. **Internal Types:** Backward compatibility only applies to public types and members. Internal types are excluded from compatibility processing. - -4. **Custom Code:** If you have customized a type or method, the backward compatibility system may not be able to generate appropriate compatibility shims. Manual adjustments may be needed. - -### Testing - -The generator includes comprehensive tests for backward compatibility scenarios: - -- **Test Location:** `/test/Providers/ModelFactories/ModelFactoryProviderTests.cs` -- **Test Methods:** - - `BackCompatibility_NewModelPropertyAdded` - Tests factory methods when properties are added - - `BackCompatibility_OnlyParamOrderingChanged` - Tests parameter ordering preservation - - `BackCompatibility_NoCurrentOverloadFound` - Tests renamed method handling - -Run these tests to validate backward compatibility behavior: -```bash -# From the generator root directory -dotnet test --filter "FullyQualifiedName~ModelFactoryProviderTests.BackCompatibility" -``` From dfaed6bf091d0ffddb72245c8662aa425af874a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Oct 2025 16:29:27 +0000 Subject: [PATCH 5/9] Revert removal of Scenario 3 and fix typo Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index 731bc9254a2..f027a8b398b 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -27,7 +27,7 @@ When generating code, the generator can optionally receive a compiled assembly f ### Model Factory Methods -Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator attempts to maintains backward compatibility for these methods across API changes. +Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator attempts to maintain backward compatibility for these methods across API changes. #### Scenario 1: New Model Property Added @@ -96,6 +96,40 @@ public static PublicModel1 PublicModel1( **Result:** The generator keeps the previous parameter ordering to maintain compatibility. +#### Scenario 3: Model Factory Method Renamed + +**Description:** When a model or factory method is renamed, the generator creates a compatibility method with the old name that instantiates the new model type. + +**Example:** + +Previous version: +```csharp +public static PublicModel1 PublicModel1OldName(string stringProp = default) +``` + +Current version: +```csharp +public static PublicModel1 PublicModel1( + string stringProp = default, + Thing modelProp = default, + IEnumerable listProp = default, + IDictionary dictProp = default) +``` + +**Generated Compatibility Method:** +```csharp +[EditorBrowsable(EditorBrowsableState.Never)] +public static PublicModel1 PublicModel1OldName(string stringProp) +{ + return new PublicModel1(stringProp, default, default, default); +} +``` + +**Key Points:** +- The old method name is preserved +- The method creates an instance of the new model type +- Missing parameters are filled with default values + ### Model Properties The generator attempts to maintain backward compatibility for model property types, particularly for collection types. From cc1015c28a9bc42463db760fbf3998a586214347 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Oct 2025 15:34:49 +0000 Subject: [PATCH 6/9] Run prettier to fix markdown formatting Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index f027a8b398b..9952d26b306 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -36,6 +36,7 @@ Model factory methods are public static methods that enable creating model insta **Example:** Previous version had a model with three properties: + ```csharp public static PublicModel1 PublicModel1( string stringProp = default, @@ -44,6 +45,7 @@ public static PublicModel1 PublicModel1( ``` Current version adds a new property (`dictProp`): + ```csharp public static PublicModel1 PublicModel1( string stringProp = default, @@ -53,6 +55,7 @@ public static PublicModel1 PublicModel1( ``` **Generated Compatibility Method:** + ```csharp [EditorBrowsable(EditorBrowsableState.Never)] public static PublicModel1 PublicModel1( @@ -65,6 +68,7 @@ public static PublicModel1 PublicModel1( ``` **Key Points:** + - The old method signature is preserved - It delegates to the new method with default value for the new parameter - Parameters in the compatibility method have no default values to avoid ambiguous call sites @@ -77,6 +81,7 @@ public static PublicModel1 PublicModel1( **Example:** Previous version: + ```csharp public static PublicModel1 PublicModel1( Thing modelProp = default, @@ -86,6 +91,7 @@ public static PublicModel1 PublicModel1( ``` Current version would generate different ordering: + ```csharp public static PublicModel1 PublicModel1( string stringProp = default, @@ -103,11 +109,13 @@ public static PublicModel1 PublicModel1( **Example:** Previous version: + ```csharp public static PublicModel1 PublicModel1OldName(string stringProp = default) ``` Current version: + ```csharp public static PublicModel1 PublicModel1( string stringProp = default, @@ -117,6 +125,7 @@ public static PublicModel1 PublicModel1( ``` **Generated Compatibility Method:** + ```csharp [EditorBrowsable(EditorBrowsableState.Never)] public static PublicModel1 PublicModel1OldName(string stringProp) @@ -126,6 +135,7 @@ public static PublicModel1 PublicModel1OldName(string stringProp) ``` **Key Points:** + - The old method name is preserved - The method creates an instance of the new model type - Missing parameters are filled with default values @@ -141,21 +151,25 @@ The generator attempts to maintain backward compatibility for model property typ **Example:** Previous version: + ```csharp public IReadOnlyList Items { get; } ``` Current TypeSpec would generate: + ```csharp public IList Items { get; set; } ``` **Result:** The generator detects the type mismatch and preserves the previous type: + ```csharp public IReadOnlyList Items { get; } ``` **Implementation Details:** + - The generator compares property types against the `LastContractView` - For read-write lists and dictionaries, if the previous type was different, the previous type is retained - A diagnostic message is logged: `"Changed property {ModelName}.{PropertyName} type to {LastContractType} to match last contract."` @@ -171,6 +185,7 @@ Service version enums maintain backward compatibility by preserving version valu **Example:** Previous version had enum members: + ```csharp public enum ServiceVersion { @@ -181,6 +196,7 @@ public enum ServiceVersion ``` Current TypeSpec removes `V2021_10_01` and adds `V2023_01_01`: + ```csharp public enum ServiceVersion { @@ -191,6 +207,7 @@ public enum ServiceVersion ``` **Generated Result:** + ```csharp public enum ServiceVersion { @@ -202,6 +219,7 @@ public enum ServiceVersion ``` **Key Points:** + - Previous enum members are preserved even if removed from TypeSpec - Enum values are re-indexed to maintain sequential ordering - Version format and separator are detected from current versions and applied to previous versions From 9c2d956ef6ce00c35c774cf3e565a4fd53a1f0bb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:28:55 +0000 Subject: [PATCH 7/9] Remove Scenario 3 (Model Factory Method Renamed) Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index 9952d26b306..f00826cbb7f 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -102,44 +102,6 @@ public static PublicModel1 PublicModel1( **Result:** The generator keeps the previous parameter ordering to maintain compatibility. -#### Scenario 3: Model Factory Method Renamed - -**Description:** When a model or factory method is renamed, the generator creates a compatibility method with the old name that instantiates the new model type. - -**Example:** - -Previous version: - -```csharp -public static PublicModel1 PublicModel1OldName(string stringProp = default) -``` - -Current version: - -```csharp -public static PublicModel1 PublicModel1( - string stringProp = default, - Thing modelProp = default, - IEnumerable listProp = default, - IDictionary dictProp = default) -``` - -**Generated Compatibility Method:** - -```csharp -[EditorBrowsable(EditorBrowsableState.Never)] -public static PublicModel1 PublicModel1OldName(string stringProp) -{ - return new PublicModel1(stringProp, default, default, default); -} -``` - -**Key Points:** - -- The old method name is preserved -- The method creates an instance of the new model type -- Missing parameters are filled with default values - ### Model Properties The generator attempts to maintain backward compatibility for model property types, particularly for collection types. From 0bb132094ee69568d53791608eeda5b814597a67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:48:38 +0000 Subject: [PATCH 8/9] Remove scenario numbers from sub-headers Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index f00826cbb7f..964f632cb27 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -29,7 +29,7 @@ When generating code, the generator can optionally receive a compiled assembly f Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator attempts to maintain backward compatibility for these methods across API changes. -#### Scenario 1: New Model Property Added +#### New Model Property Added **Description:** When a new property is added to a model, the generator creates a backward-compatible factory method overload that excludes the new parameter. @@ -74,7 +74,7 @@ public static PublicModel1 PublicModel1( - Parameters in the compatibility method have no default values to avoid ambiguous call sites - The method is marked with `[EditorBrowsable(EditorBrowsableState.Never)]` to hide it from IntelliSense -#### Scenario 2: Parameter Ordering Changed +#### Parameter Ordering Changed **Description:** When only the parameter ordering changes in a factory method (same parameters, different order), the generator replaces the current method with the previous method signature. @@ -106,7 +106,7 @@ public static PublicModel1 PublicModel1( The generator attempts to maintain backward compatibility for model property types, particularly for collection types. -#### Scenario: Collection Property Type Changed +#### Collection Property Type Changed **Description:** When a property type changes from a read-only collection to a read-write collection (or vice versa), the generator attempts to preserve the previous property type to avoid breaking changes. @@ -140,7 +140,7 @@ public IReadOnlyList Items { get; } Service version enums maintain backward compatibility by preserving version values from previous releases. -#### Scenario: API Version Removed or Changed +#### API Version Removed or Changed **Description:** When API versions are removed or changed in the TypeSpec, the generator preserves previous version enum members to prevent breaking existing code that references them. From 01678e344e996d5dfc68d2a3dfdde3730ad5ee24 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:54:13 +0000 Subject: [PATCH 9/9] Add 'Scenario:' prefix back to sub-headers Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../generator/docs/backward-compatibility.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/http-client-csharp/generator/docs/backward-compatibility.md b/packages/http-client-csharp/generator/docs/backward-compatibility.md index 964f632cb27..72716b69df6 100644 --- a/packages/http-client-csharp/generator/docs/backward-compatibility.md +++ b/packages/http-client-csharp/generator/docs/backward-compatibility.md @@ -29,7 +29,7 @@ When generating code, the generator can optionally receive a compiled assembly f Model factory methods are public static methods that enable creating model instances for mocking and testing purposes. The generator attempts to maintain backward compatibility for these methods across API changes. -#### New Model Property Added +#### Scenario: New Model Property Added **Description:** When a new property is added to a model, the generator creates a backward-compatible factory method overload that excludes the new parameter. @@ -74,7 +74,7 @@ public static PublicModel1 PublicModel1( - Parameters in the compatibility method have no default values to avoid ambiguous call sites - The method is marked with `[EditorBrowsable(EditorBrowsableState.Never)]` to hide it from IntelliSense -#### Parameter Ordering Changed +#### Scenario: Parameter Ordering Changed **Description:** When only the parameter ordering changes in a factory method (same parameters, different order), the generator replaces the current method with the previous method signature. @@ -106,7 +106,7 @@ public static PublicModel1 PublicModel1( The generator attempts to maintain backward compatibility for model property types, particularly for collection types. -#### Collection Property Type Changed +#### Scenario: Collection Property Type Changed **Description:** When a property type changes from a read-only collection to a read-write collection (or vice versa), the generator attempts to preserve the previous property type to avoid breaking changes. @@ -140,7 +140,7 @@ public IReadOnlyList Items { get; } Service version enums maintain backward compatibility by preserving version values from previous releases. -#### API Version Removed or Changed +#### Scenario: API Version Removed or Changed **Description:** When API versions are removed or changed in the TypeSpec, the generator preserves previous version enum members to prevent breaking existing code that references them.