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
27 changes: 26 additions & 1 deletion src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ private static void GenerateDocCommentsProperties(JsonObject propertyNode, strin
propertyNode["description"] = builder.ToString();
}

if (propertyNode["type"]?.GetValue<string>() == "boolean")
var propertyNodeType = propertyNode["type"];
if (propertyNodeType?.GetValueKind() == JsonValueKind.String && propertyNodeType.GetValue<string>() == "boolean")
{
var value = memberRoot.Element("value")?.ToString();
if (value?.Contains("default value is", StringComparison.OrdinalIgnoreCase) == true)
Expand Down Expand Up @@ -428,6 +429,18 @@ private void AppendParsableFromString(JsonObject propertyNode, ParsableFromStrin
propertyNode["type"] = "string";
propertyNode["format"] = "uri";
}
else if (parsable.DisplayString == "float" ||
parsable.DisplayString == "double" ||
parsable.DisplayString == "decimal" ||
parsable.DisplayString == "Half")
{
propertyNode["type"] = new JsonArray { "number", "string" };
}
else if (parsable.DisplayString == "Guid")
{
propertyNode["type"] = "string";
propertyNode["format"] = "uuid";
}
else
{
propertyNode["type"] = GetParsableTypeName(parsable);
Expand All @@ -437,13 +450,25 @@ private void AppendParsableFromString(JsonObject propertyNode, ParsableFromStrin
private static string GetParsableTypeName(ParsableFromStringSpec parsable) => parsable.DisplayString switch
{
"bool" => "boolean",
"byte" => "integer",
"sbyte" => "integer",
"char" => "integer",
"short" => "integer",
"ushort" => "integer",
"int" => "integer",
"uint" => "integer",
"long" => "integer",
"ulong" => "integer",
"Int128" => "integer",
"UInt128" => "integer",
"string" => "string",
"Version" => "string",
"DateTime" => "string",
"DateTimeOffset" => "string",
"DateOnly" => "string",
"TimeOnly" => "string",
"object" => "string",
"CultureInfo" => "string",
_ => throw new InvalidOperationException($"Unknown parsable type {parsable.DisplayString}")
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
{
"properties": {
"RecordWithPrimitives": {
"type": "object",
"properties": {
"Prop0": {
"type": "boolean",
"description": "Prop0 is a bool."
},
"Prop1": {
"type": "integer"
},
"Prop10": {
"type": [
"number",
"string"
],
"description": "Prop10 is a float."
},
"Prop11": {
"type": [
"number",
"string"
]
},
"Prop12": {
"type": "integer"
},
"Prop13": {
"type": "integer"
},
"Prop14": {
"type": "integer"
},
"Prop15": {
"type": "integer"
},
"Prop16": {
"type": "string"
},
"Prop17": {
"type": "string"
},
"Prop18": {
"type": "string"
},
"Prop19": {
"type": "string"
},
"Prop2": {
"type": "integer"
},
"Prop20": {
"type": "string"
},
"Prop21": {
"type": [
"number",
"string"
]
},
"Prop22": {
"type": "string"
},
"Prop23": {
"type": "string",
"format": "duration"
},
"Prop24": {
"type": "string",
"format": "uuid"
},
"Prop25": {
"type": "string",
"format": "uri"
},
"Prop26": {
"type": "string"
},
"Prop27": {
"enum": [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
]
},
"Prop3": {
"type": "integer"
},
"Prop4": {
"type": [
"number",
"string"
]
},
"Prop5": {
"type": "string"
},
"Prop6": {
"type": "integer"
},
"Prop7": {
"type": "integer"
},
"Prop8": {
"type": "integer"
},
"Prop9": {
"type": "integer"
}
}
}
},
"type": "object"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@

<PropertyGroup>
<TargetFramework>$(NetCurrent)</TargetFramework>

<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\..\src\Components\Common\ConfigurationSchemaAttributes.cs" Link="ConfigurationSchemaAttributes.cs" />

<Content Include="Baselines\**\*;">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.DotNet.XUnitExtensions" />
</ItemGroup>
Expand Down
18 changes: 18 additions & 0 deletions tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,22 @@ public void StripXmlElementsShouldNotFormatMiscAttributes(string input, string e
var first = stripedNodes.First();
Assert.Equal(expected, first.ToString().Trim());
}

[Fact]
public void IntegrationTest()
{
// the 'refs' folder is populated by PreserveCompilationContext in the .csproj
var referenceAssemblies = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "refs"), "*.dll", SearchOption.AllDirectories)
.ToArray();

var outputPath = Path.Combine(Directory.GetCurrentDirectory(), "IntegrationTest.json");
ConfigSchemaGenerator.GenerateSchema(
typeof(GeneratorTests).Assembly.Location,
referenceAssemblies,
outputPath);

var actual = File.ReadAllText(outputPath);
var baseline = File.ReadAllText(Path.Combine("Baselines", "IntegrationTest.baseline.json"));
Assert.Equal(baseline, actual);
}
}
50 changes: 50 additions & 0 deletions tests/ConfigurationSchemaGenerator.Tests/RecordWithPrimitives.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Globalization;
using Aspire;
using ConfigurationSchemaGenerator.Tests;

[assembly: ConfigurationSchema("RecordWithPrimitives", typeof(RecordWithPrimitives))]

namespace ConfigurationSchemaGenerator.Tests;

public record RecordWithPrimitives
{
/// <summary>
/// Prop0 is a bool.
/// </summary>
public bool Prop0 { get; set; }
public byte Prop1 { get; set; }
public sbyte Prop2 { get; set; }
public char Prop3 { get; set; }
public double Prop4 { get; set; }
public string? Prop5 { get; set; }
public int Prop6 { get; set; }
public short Prop8 { get; set; }
public long Prop9 { get; set; }
/// <summary>
/// Prop10 is a float.
/// </summary>
public float Prop10 { get; set; }
public ushort Prop13 { get; set; }
public uint Prop14 { get; set; }
public ulong Prop15 { get; set; }
public object? Prop16 { get; set; }
public CultureInfo? Prop17 { get; set; }
public DateTime Prop19 { get; set; }
public DateTimeOffset Prop20 { get; set; }
public decimal Prop21 { get; set; }
public TimeSpan Prop23 { get; set; }
public Guid Prop24 { get; set; }
public Uri? Prop25 { get; set; }
public Version? Prop26 { get; set; }
public DayOfWeek Prop27 { get; set; }
#if NETCOREAPP
public Int128 Prop7 { get; set; }
public Half Prop11 { get; set; }
public UInt128 Prop12 { get; set; }
public DateOnly Prop18 { get; set; }
public TimeOnly Prop22 { get; set; }
#endif
}