Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.TypeSpec.Generator.ClientModel
{
/// <summary>
/// Options that control ConfigurationSchema.json generation.
/// </summary>
public class ConfigurationSchemaOptions
{
/// <summary>
/// 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".
/// </summary>
public string SectionName { get; set; } = ConfigurationSchemaGenerator.DefaultSectionName;

/// <summary>
/// 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".
/// </summary>
public string OptionsRef { get; set; } = ConfigurationSchemaGenerator.DefaultOptionsRef;

/// <summary>
/// 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.
/// </summary>
public bool GenerateNuGetTargets { get; set; } = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class ScmCodeModelGenerator : CodeModelGenerator
internal SerializationFormatDefinition SerializationFormatDefinition { get; } =
new SerializationFormatDefinition();

/// <summary>
/// Gets the options that control ConfigurationSchema.json generation.
/// </summary>
public ConfigurationSchemaOptions ConfigurationSchema { get; } = new();

[ImportingConstructor]
public ScmCodeModelGenerator(GeneratorContext context)
: base(context)
Expand All @@ -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");
Expand All @@ -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);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,96 @@ public void GetJsonSchemaForType_ReturnsCorrectSchema_ForNullableTypes()
Assert.AreEqual("boolean", nullableBoolSchema["type"]?.GetValue<string>());
}

[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<string>();
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<string>();
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<string>());
}

[Test]
public void ConfigurationSchemaOptions_HasCorrectDefaults()
{
var options = new ConfigurationSchemaOptions();
Assert.AreEqual("Clients", options.SectionName);
Assert.AreEqual("options", options.OptionsRef);
Assert.IsTrue(options.GenerateNuGetTargets);
}

/// <summary>
/// Test output library that wraps provided TypeProviders.
/// </summary>
Expand Down
Loading