diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ConfigurationSchemaOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ConfigurationSchemaOptions.cs
new file mode 100644
index 00000000000..c1ad887b65c
--- /dev/null
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ConfigurationSchemaOptions.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Microsoft.TypeSpec.Generator.ClientModel
+{
+ ///
+ /// Options that control ConfigurationSchema.json generation.
+ ///
+ public class ConfigurationSchemaOptions
+ {
+ ///
+ /// Gets or sets the top-level section name used in the generated ConfigurationSchema.json.
+ /// Defaults to "Clients". Azure SDK generators should set this to "AzureClients".
+ ///
+ public string SectionName { get; set; } = ConfigurationSchemaGenerator.DefaultSectionName;
+
+ ///
+ /// Gets or sets the $ref value used for the base options definition in the generated ConfigurationSchema.json.
+ /// Defaults to "options". Azure SDK generators should set this to "azureOptions".
+ ///
+ public string OptionsRef { get; set; } = ConfigurationSchemaGenerator.DefaultOptionsRef;
+
+ ///
+ /// Gets or sets whether to generate the .NuGet.targets file alongside the ConfigurationSchema.json.
+ /// Defaults to true. Set to false when the build infrastructure handles targets file packing centrally.
+ ///
+ public bool GenerateNuGetTargets { get; set; } = true;
+ }
+}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs
index 880545ed93c..5725dedc32f 100644
--- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmCodeModelGenerator.cs
@@ -30,6 +30,11 @@ public class ScmCodeModelGenerator : CodeModelGenerator
internal SerializationFormatDefinition SerializationFormatDefinition { get; } =
new SerializationFormatDefinition();
+ ///
+ /// Gets the options that control ConfigurationSchema.json generation.
+ ///
+ public ConfigurationSchemaOptions ConfigurationSchema { get; } = new();
+
[ImportingConstructor]
public ScmCodeModelGenerator(GeneratorContext context)
: base(context)
@@ -49,7 +54,10 @@ protected override void Configure()
public override async Task WriteAdditionalFiles(string outputPath)
{
- var schemaContent = ConfigurationSchemaGenerator.Generate(OutputLibrary);
+ var schemaContent = ConfigurationSchemaGenerator.Generate(
+ OutputLibrary,
+ ConfigurationSchema.SectionName,
+ ConfigurationSchema.OptionsRef);
if (schemaContent != null)
{
var schemaPath = Path.Combine(outputPath, "schema", "ConfigurationSchema.json");
@@ -61,12 +69,15 @@ public override async Task WriteAdditionalFiles(string outputPath)
Emitter.Info($"Writing {Path.GetFullPath(schemaPath)}");
await File.WriteAllTextAsync(schemaPath, schemaContent);
- // Generate the .targets file for JsonSchemaSegment registration
- var packageName = Configuration.PackageName;
- var targetsPath = Path.Combine(outputPath, $"{packageName}.NuGet.targets");
- var targetsContent = GenerateTargetsFile();
- Emitter.Info($"Writing {Path.GetFullPath(targetsPath)}");
- await File.WriteAllTextAsync(targetsPath, targetsContent);
+ if (ConfigurationSchema.GenerateNuGetTargets)
+ {
+ // Generate the .targets file for JsonSchemaSegment registration
+ var packageName = Configuration.PackageName;
+ var targetsPath = Path.Combine(outputPath, $"{packageName}.NuGet.targets");
+ var targetsContent = GenerateTargetsFile();
+ Emitter.Info($"Writing {Path.GetFullPath(targetsPath)}");
+ await File.WriteAllTextAsync(targetsPath, targetsContent);
+ }
}
}
diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ConfigurationSchemaGeneratorTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ConfigurationSchemaGeneratorTests.cs
index e118f3fd6dd..dbc47ede7e8 100644
--- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ConfigurationSchemaGeneratorTests.cs
+++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ConfigurationSchemaGeneratorTests.cs
@@ -749,6 +749,96 @@ public void GetJsonSchemaForType_ReturnsCorrectSchema_ForNullableTypes()
Assert.AreEqual("boolean", nullableBoolSchema["type"]?.GetValue());
}
+ [Test]
+ public void Generate_UsesCustomSectionName()
+ {
+ var client = InputFactory.Client("TestService");
+ var clientProvider = new ClientProvider(client);
+
+ var output = new TestOutputLibrary([clientProvider]);
+ var result = ConfigurationSchemaGenerator.Generate(output, sectionName: "AzureClients");
+
+ Assert.IsNotNull(result);
+ var doc = JsonNode.Parse(result!)!;
+
+ Assert.IsNull(doc["properties"]?["Clients"], "Schema should not have a 'Clients' section");
+ var azureClients = doc["properties"]?["AzureClients"];
+ Assert.IsNotNull(azureClients, "Schema should have an 'AzureClients' section");
+
+ var testClient = azureClients!["properties"]?["TestService"];
+ Assert.IsNotNull(testClient, "Schema should have a well-known 'TestService' entry under AzureClients");
+ }
+
+ [Test]
+ public void Generate_UsesCustomOptionsRef()
+ {
+ var client = InputFactory.Client("TestService");
+ var clientProvider = new ClientProvider(client);
+
+ var output = new TestOutputLibrary([clientProvider]);
+ var result = ConfigurationSchemaGenerator.Generate(output, optionsRef: "azureOptions");
+
+ Assert.IsNotNull(result);
+ var doc = JsonNode.Parse(result!)!;
+
+ // The options definition should inherit from azureOptions instead of options
+ var definitions = doc["definitions"];
+ Assert.IsNotNull(definitions);
+
+ // Find the client options definition and verify it references azureOptions
+ foreach (var def in definitions!.AsObject())
+ {
+ var allOf = def.Value?["allOf"];
+ if (allOf != null)
+ {
+ var baseRef = allOf.AsArray()[0]?["$ref"]?.GetValue();
+ Assert.AreEqual("#/definitions/azureOptions", baseRef,
+ $"Definition '{def.Key}' should reference azureOptions");
+ }
+ }
+ }
+
+ [Test]
+ public void Generate_UsesCustomSectionNameAndOptionsRef()
+ {
+ var client = InputFactory.Client("TestService");
+ var clientProvider = new ClientProvider(client);
+
+ var output = new TestOutputLibrary([clientProvider]);
+ var result = ConfigurationSchemaGenerator.Generate(
+ output,
+ sectionName: "AzureClients",
+ optionsRef: "azureOptions");
+
+ Assert.IsNotNull(result);
+ var doc = JsonNode.Parse(result!)!;
+
+ // Verify section name
+ Assert.IsNull(doc["properties"]?["Clients"]);
+ Assert.IsNotNull(doc["properties"]?["AzureClients"]);
+
+ // Verify options ref
+ var clientEntry = doc["properties"]?["AzureClients"]?["properties"]?["TestService"];
+ Assert.IsNotNull(clientEntry);
+
+ // The options definition should use azureOptions
+ var optionsRef = clientEntry!["properties"]?["Options"]?["$ref"]?.GetValue();
+ Assert.IsNotNull(optionsRef);
+ var defName = optionsRef!.Replace("#/definitions/", "");
+ var optionsDef = doc["definitions"]?[defName];
+ Assert.IsNotNull(optionsDef);
+ Assert.AreEqual("#/definitions/azureOptions", optionsDef!["allOf"]?.AsArray()[0]?["$ref"]?.GetValue());
+ }
+
+ [Test]
+ public void ConfigurationSchemaOptions_HasCorrectDefaults()
+ {
+ var options = new ConfigurationSchemaOptions();
+ Assert.AreEqual("Clients", options.SectionName);
+ Assert.AreEqual("options", options.OptionsRef);
+ Assert.IsTrue(options.GenerateNuGetTargets);
+ }
+
///
/// Test output library that wraps provided TypeProviders.
///