From 7ca28b913d72a5b448f6cbbe7361cf2bfc0cc37c Mon Sep 17 00:00:00 2001 From: Kia Rad Date: Wed, 20 Dec 2023 18:02:44 +0330 Subject: [PATCH 1/7] Trim Property or Type namespace from summaries when generating description from xml docs --- .../ConfigurationSchema.json | 8 ++++---- .../ConfigurationSchema.json | 4 ++-- .../ConfigurationSchema.json | 8 ++++---- .../ConfigurationSchema.json | 16 ++++++++-------- .../ConfigurationSchema.json | 12 ++++++------ .../ConfigurationSchema.json | 2 +- .../ConfigurationSchema.json | 2 +- .../ConfigurationSchema.json | 18 +++++++++--------- .../ConfigurationSchema.json | 6 +++--- .../ConfigSchemaEmitter.cs | 13 +++++++++++++ .../GeneratorTests.cs | 15 +++++++++++++++ 11 files changed, 66 insertions(+), 38 deletions(-) diff --git a/src/Components/Aspire.Azure.Data.Tables/ConfigurationSchema.json b/src/Components/Aspire.Azure.Data.Tables/ConfigurationSchema.json index dc5c8ccf36..61ec8f5e20 100644 --- a/src/Components/Aspire.Azure.Data.Tables/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Data.Tables/ConfigurationSchema.json @@ -35,7 +35,7 @@ "properties": { "ApplicationId": { "type": "string", - "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to P:Azure.Core.DiagnosticsOptions.DefaultApplicationId." + "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to 'Azure.Core.DiagnosticsOptions.DefaultApplicationId'." }, "DefaultApplicationId": { "type": "string", @@ -43,7 +43,7 @@ }, "IsDistributedTracingEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether distributed tracing activities ( T:System.Diagnostics.Activity ) are going to be created for the clients methods calls and HTTP calls." + "description": "Gets or sets value indicating whether distributed tracing activities ( 'System.Diagnostics.Activity' ) are going to be created for the clients methods calls and HTTP calls." }, "IsLoggingContentEnabled": { "type": "boolean", @@ -55,7 +55,7 @@ }, "IsTelemetryEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether the \"User-Agent\" header containing P:Azure.Core.DiagnosticsOptions.ApplicationId , client library package name and version, P:System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription and P:System.Runtime.InteropServices.RuntimeInformation.OSDescription should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." + "description": "Gets or sets value indicating whether the \"User-Agent\" header containing 'Azure.Core.DiagnosticsOptions.ApplicationId' , client library package name and version, 'System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription' and 'System.Runtime.InteropServices.RuntimeInformation.OSDescription' should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." }, "LoggedContentSizeLimit": { "type": "integer", @@ -115,7 +115,7 @@ "ServiceUri": { "type": "string", "format": "uri", - "description": "A T:System.Uri referencing the table service account.\nThis is likely to be similar to \"https://{account_name}.table.core.windows.net/\" or \"https://{account_name}.table.cosmos.azure.com/\"." + "description": "A 'System.Uri' referencing the table service account.\nThis is likely to be similar to \"https://{account_name}.table.core.windows.net/\" or \"https://{account_name}.table.cosmos.azure.com/\"." }, "Tracing": { "type": "boolean", diff --git a/src/Components/Aspire.Azure.Messaging.ServiceBus/ConfigurationSchema.json b/src/Components/Aspire.Azure.Messaging.ServiceBus/ConfigurationSchema.json index 4d6f91c579..c2928f31ee 100644 --- a/src/Components/Aspire.Azure.Messaging.ServiceBus/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Messaging.ServiceBus/ConfigurationSchema.json @@ -49,7 +49,7 @@ }, "Identifier": { "type": "string", - "description": "A property used to set the T:Azure.Messaging.ServiceBus.ServiceBusClient ID to identify the client. This can be used to correlate logs\nand exceptions. If null or empty, a random unique value will be used." + "description": "A property used to set the 'Azure.Messaging.ServiceBus.ServiceBusClient' ID to identify the client. This can be used to correlate logs\nand exceptions. If null or empty, a random unique value will be used." }, "RetryOptions": { "type": "object", @@ -91,7 +91,7 @@ "description": "The type of protocol and transport that will be used for communicating with the Service Bus\nservice." } }, - "description": "The set of options that can be specified when creating an T:Azure.Messaging.ServiceBus.ServiceBusConnection to configure its behavior." + "description": "The set of options that can be specified when creating an 'Azure.Messaging.ServiceBus.ServiceBusConnection' to configure its behavior." }, "ConnectionString": { "type": "string", diff --git a/src/Components/Aspire.Azure.Security.KeyVault/ConfigurationSchema.json b/src/Components/Aspire.Azure.Security.KeyVault/ConfigurationSchema.json index 17e335b5a9..dc868a6c6f 100644 --- a/src/Components/Aspire.Azure.Security.KeyVault/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Security.KeyVault/ConfigurationSchema.json @@ -35,7 +35,7 @@ "properties": { "ApplicationId": { "type": "string", - "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to P:Azure.Core.DiagnosticsOptions.DefaultApplicationId." + "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to 'Azure.Core.DiagnosticsOptions.DefaultApplicationId'." }, "DefaultApplicationId": { "type": "string", @@ -43,7 +43,7 @@ }, "IsDistributedTracingEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether distributed tracing activities ( T:System.Diagnostics.Activity ) are going to be created for the clients methods calls and HTTP calls." + "description": "Gets or sets value indicating whether distributed tracing activities ( 'System.Diagnostics.Activity' ) are going to be created for the clients methods calls and HTTP calls." }, "IsLoggingContentEnabled": { "type": "boolean", @@ -55,7 +55,7 @@ }, "IsTelemetryEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether the \"User-Agent\" header containing P:Azure.Core.DiagnosticsOptions.ApplicationId , client library package name and version, P:System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription and P:System.Runtime.InteropServices.RuntimeInformation.OSDescription should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." + "description": "Gets or sets value indicating whether the \"User-Agent\" header containing 'Azure.Core.DiagnosticsOptions.ApplicationId' , client library package name and version, 'System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription' and 'System.Runtime.InteropServices.RuntimeInformation.OSDescription' should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." }, "LoggedContentSizeLimit": { "type": "integer", @@ -116,7 +116,7 @@ "VaultUri": { "type": "string", "format": "uri", - "description": "A T:System.Uri to the vault on which the client operates. Appears as \"DNS Name\" in the Azure portal.\nIf you have a secret T:System.Uri , use T:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier to parse the P:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri and other information.\nYou should validate that this URI references a valid Key Vault resource. See https://aka.ms/azsdk/blog/vault-uri for details." + "description": "A 'System.Uri' to the vault on which the client operates. Appears as \"DNS Name\" in the Azure portal.\nIf you have a secret 'System.Uri' , use 'Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier' to parse the 'Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri' and other information.\nYou should validate that this URI references a valid Key Vault resource. See https://aka.ms/azsdk/blog/vault-uri for details." } }, "description": "Provides the client configuration settings for connecting to Azure Key Vault." diff --git a/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json b/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json index 24f987cb0d..ab8f64a328 100644 --- a/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json @@ -35,7 +35,7 @@ "properties": { "ApplicationId": { "type": "string", - "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to P:Azure.Core.DiagnosticsOptions.DefaultApplicationId." + "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to 'Azure.Core.DiagnosticsOptions.DefaultApplicationId'." }, "DefaultApplicationId": { "type": "string", @@ -43,7 +43,7 @@ }, "IsDistributedTracingEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether distributed tracing activities ( T:System.Diagnostics.Activity ) are going to be created for the clients methods calls and HTTP calls." + "description": "Gets or sets value indicating whether distributed tracing activities ( 'System.Diagnostics.Activity' ) are going to be created for the clients methods calls and HTTP calls." }, "IsLoggingContentEnabled": { "type": "boolean", @@ -55,7 +55,7 @@ }, "IsTelemetryEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether the \"User-Agent\" header containing P:Azure.Core.DiagnosticsOptions.ApplicationId , client library package name and version, P:System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription and P:System.Runtime.InteropServices.RuntimeInformation.OSDescription should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." + "description": "Gets or sets value indicating whether the \"User-Agent\" header containing 'Azure.Core.DiagnosticsOptions.ApplicationId' , client library package name and version, 'System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription' and 'System.Runtime.InteropServices.RuntimeInformation.OSDescription' should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." }, "LoggedContentSizeLimit": { "type": "integer", @@ -70,12 +70,12 @@ }, "EncryptionScope": { "type": "string", - "description": "Gets the P:Azure.Storage.Blobs.BlobClientOptions.EncryptionScope to be used when making requests." + "description": "Gets the 'Azure.Storage.Blobs.BlobClientOptions.EncryptionScope' to be used when making requests." }, "GeoRedundantSecondaryUri": { "type": "string", "format": "uri", - "description": "Gets or sets the secondary storage T:System.Uri that can be read from for the storage account if the\naccount is enabled for RA-GRS.\n\nIf this property is set, the secondary Uri will be used for GET or HEAD requests during retries.\nIf the status of the response from the secondary Uri is a 404, then subsequent retries for\nthe request will not use the secondary Uri again, as this indicates that the resource\nmay not have propagated there yet. Otherwise, subsequent retries will alternate back and forth\nbetween primary and secondary Uri." + "description": "Gets or sets the secondary storage 'System.Uri' that can be read from for the storage account if the\naccount is enabled for RA-GRS.\n\nIf this property is set, the secondary Uri will be used for GET or HEAD requests during retries.\nIf the status of the response from the secondary Uri is a 404, then subsequent retries for\nthe request will not use the secondary Uri again, as this indicates that the resource\nmay not have propagated there yet. Otherwise, subsequent retries will alternate back and forth\nbetween primary and secondary Uri." }, "Retry": { "type": "object", @@ -117,7 +117,7 @@ "properties": { "AutoValidateChecksum": { "type": "boolean", - "description": "Defaults to true. False can only be specified on specific operations and not at the client level.\nIndicates whether the SDK should validate the content\nbody against the content hash before returning contents to the caller.\nIf set to false, caller is responsible for extracting the hash out\nof the T:Azure.Response`1 and validating the hash themselves." + "description": "Defaults to true. False can only be specified on specific operations and not at the client level.\nIndicates whether the SDK should validate the content\nbody against the content hash before returning contents to the caller.\nIf set to false, caller is responsible for extracting the hash out\nof the 'Azure.Response`1' and validating the hash themselves." }, "ChecksumAlgorithm": { "enum": [ @@ -151,7 +151,7 @@ }, "TrimBlobNameSlashes": { "type": "boolean", - "description": "Whether to trim leading and trailing slashes on a blob name when using M:Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String) and similar methods.\nDefaults to true for backwards compatibility." + "description": "Whether to trim leading and trailing slashes on a blob name when using 'Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String)' and similar methods.\nDefaults to true for backwards compatibility." } }, "description": "Provides the client configuration options for connecting to Azure Blob\nStorage." @@ -168,7 +168,7 @@ "ServiceUri": { "type": "string", "format": "uri", - "description": "A T:System.Uri referencing the blob service.\nThis is likely to be similar to \"https://{account_name}.blob.core.windows.net\"." + "description": "A 'System.Uri' referencing the blob service.\nThis is likely to be similar to \"https://{account_name}.blob.core.windows.net\"." }, "Tracing": { "type": "boolean", diff --git a/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json b/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json index d13d6e3de4..88f50fb474 100644 --- a/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json @@ -35,7 +35,7 @@ "properties": { "ApplicationId": { "type": "string", - "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to P:Azure.Core.DiagnosticsOptions.DefaultApplicationId." + "description": "Gets or sets the value sent as the first part of \"User-Agent\" headers for all requests issues by this client. Defaults to 'Azure.Core.DiagnosticsOptions.DefaultApplicationId'." }, "DefaultApplicationId": { "type": "string", @@ -43,7 +43,7 @@ }, "IsDistributedTracingEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether distributed tracing activities ( T:System.Diagnostics.Activity ) are going to be created for the clients methods calls and HTTP calls." + "description": "Gets or sets value indicating whether distributed tracing activities ( 'System.Diagnostics.Activity' ) are going to be created for the clients methods calls and HTTP calls." }, "IsLoggingContentEnabled": { "type": "boolean", @@ -55,7 +55,7 @@ }, "IsTelemetryEnabled": { "type": "boolean", - "description": "Gets or sets value indicating whether the \"User-Agent\" header containing P:Azure.Core.DiagnosticsOptions.ApplicationId , client library package name and version, P:System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription and P:System.Runtime.InteropServices.RuntimeInformation.OSDescription should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." + "description": "Gets or sets value indicating whether the \"User-Agent\" header containing 'Azure.Core.DiagnosticsOptions.ApplicationId' , client library package name and version, 'System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription' and 'System.Runtime.InteropServices.RuntimeInformation.OSDescription' should be sent.\nThe default value can be controlled process wide by setting AZURE_TELEMETRY_DISABLED to true , false , 1 or 0." }, "LoggedContentSizeLimit": { "type": "integer", @@ -71,14 +71,14 @@ "GeoRedundantSecondaryUri": { "type": "string", "format": "uri", - "description": "Gets or sets the secondary storage T:System.Uri that can be read from for the storage account if the\naccount is enabled for RA-GRS.\n\nIf this property is set, the secondary Uri will be used for GET or HEAD requests during retries.\nIf the status of the response from the secondary Uri is a 404, then subsequent retries for\nthe request will not use the secondary Uri again, as this indicates that the resource\nmay not have propagated there yet. Otherwise, subsequent retries will alternate back and forth\nbetween primary and secondary Uri." + "description": "Gets or sets the secondary storage 'System.Uri' that can be read from for the storage account if the\naccount is enabled for RA-GRS.\n\nIf this property is set, the secondary Uri will be used for GET or HEAD requests during retries.\nIf the status of the response from the secondary Uri is a 404, then subsequent retries for\nthe request will not use the secondary Uri again, as this indicates that the resource\nmay not have propagated there yet. Otherwise, subsequent retries will alternate back and forth\nbetween primary and secondary Uri." }, "MessageEncoding": { "enum": [ "None", "Base64" ], - "description": "Gets or sets a message encoding that determines how P:Azure.Storage.Queues.Models.QueueMessage.Body is represented in HTTP requests and responses.\nThe default is F:Azure.Storage.Queues.QueueMessageEncoding.None." + "description": "Gets or sets a message encoding that determines how 'Azure.Storage.Queues.Models.QueueMessage.Body' is represented in HTTP requests and responses.\nThe default is 'Azure.Storage.Queues.QueueMessageEncoding.None'." }, "Retry": { "type": "object", @@ -127,7 +127,7 @@ "ServiceUri": { "type": "string", "format": "uri", - "description": "A T:System.Uri referencing the queue service.\nThis is likely to be similar to \"https://{account_name}.queue.core.windows.net\"." + "description": "A 'System.Uri' referencing the queue service.\nThis is likely to be similar to \"https://{account_name}.queue.core.windows.net\"." }, "Tracing": { "type": "boolean", diff --git a/src/Components/Aspire.Microsoft.Azure.Cosmos/ConfigurationSchema.json b/src/Components/Aspire.Microsoft.Azure.Cosmos/ConfigurationSchema.json index 1c6a3f88e0..ba3eece072 100644 --- a/src/Components/Aspire.Microsoft.Azure.Cosmos/ConfigurationSchema.json +++ b/src/Components/Aspire.Microsoft.Azure.Cosmos/ConfigurationSchema.json @@ -24,7 +24,7 @@ "AccountEndpoint": { "type": "string", "format": "uri", - "description": "A T:System.Uri referencing the Azure Cosmos DB Endpoint.\nThis is likely to be similar to \"https://{account_name}.queue.core.windows.net\"." + "description": "A 'System.Uri' referencing the Azure Cosmos DB Endpoint.\nThis is likely to be similar to \"https://{account_name}.queue.core.windows.net\"." }, "ConnectionString": { "type": "string", diff --git a/src/Components/Aspire.Microsoft.EntityFrameworkCore.Cosmos/ConfigurationSchema.json b/src/Components/Aspire.Microsoft.EntityFrameworkCore.Cosmos/ConfigurationSchema.json index 21dd3cdd01..338e52012f 100644 --- a/src/Components/Aspire.Microsoft.EntityFrameworkCore.Cosmos/ConfigurationSchema.json +++ b/src/Components/Aspire.Microsoft.EntityFrameworkCore.Cosmos/ConfigurationSchema.json @@ -42,7 +42,7 @@ "AccountEndpoint": { "type": "string", "format": "uri", - "description": "A T:System.Uri referencing the Azure Cosmos DB Endpoint.\nThis is likely to be similar to \"https://{account_name}.queue.core.windows.net\"." + "description": "A 'System.Uri' referencing the Azure Cosmos DB Endpoint.\nThis is likely to be similar to \"https://{account_name}.queue.core.windows.net\"." }, "ConnectionString": { "type": "string", diff --git a/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json b/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json index 976146344b..ea61b51bd1 100644 --- a/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json +++ b/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json @@ -44,7 +44,7 @@ }, "ConsumerDispatchConcurrency": { "type": "integer", - "description": "Set to a value greater than one to enable concurrent processing. For a concurrency greater than one T:RabbitMQ.Client.IBasicConsumer will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. T:RabbitMQ.Client.IAsyncBasicConsumer can handle concurrency much more efficiently due to the non-blocking nature of the consumer.\nDefaults to 1." + "description": "Set to a value greater than one to enable concurrent processing. For a concurrency greater than one 'RabbitMQ.Client.IBasicConsumer' will be offloaded to the worker thread pool so it is important to choose the value for the concurrency wisely to avoid thread pool overloading. 'RabbitMQ.Client.IAsyncBasicConsumer' can handle concurrency much more efficiently due to the non-blocking nature of the consumer.\nDefaults to 1." }, "ContinuationTimeout": { "type": "string", @@ -87,7 +87,7 @@ "Packet", "ControllerAreaNetwork" ], - "description": "Address family used by default.\nUse F:System.Net.Sockets.AddressFamily.InterNetwork to force to IPv4.\nUse F:System.Net.Sockets.AddressFamily.InterNetworkV6 to force to IPv6.\nOr use F:System.Net.Sockets.AddressFamily.Unknown to attempt both IPv6 and IPv4." + "description": "Address family used by default.\nUse 'System.Net.Sockets.AddressFamily.InterNetwork' to force to IPv4.\nUse 'System.Net.Sockets.AddressFamily.InterNetworkV6' to force to IPv6.\nOr use 'System.Net.Sockets.AddressFamily.Unknown' to attempt both IPv6 and IPv4." }, "DefaultAmqpUriSslProtocols": { "enum": [ @@ -104,7 +104,7 @@ }, "DispatchConsumersAsync": { "type": "boolean", - "description": "Set to true will enable a asynchronous consumer dispatcher which is compatible with T:RabbitMQ.Client.IAsyncBasicConsumer .\nDefaults to false." + "description": "Set to true will enable a asynchronous consumer dispatcher which is compatible with 'RabbitMQ.Client.IAsyncBasicConsumer' .\nDefaults to false." }, "Endpoint": { "type": "object", @@ -145,11 +145,11 @@ "Packet", "ControllerAreaNetwork" ], - "description": "Used to force the address family of the endpoint.\nUse F:System.Net.Sockets.AddressFamily.InterNetwork to force to IPv4.\nUse F:System.Net.Sockets.AddressFamily.InterNetworkV6 to force to IPv6.\nOr use F:System.Net.Sockets.AddressFamily.Unknown to attempt both IPv6 and IPv4." + "description": "Used to force the address family of the endpoint.\nUse 'System.Net.Sockets.AddressFamily.InterNetwork' to force to IPv4.\nUse 'System.Net.Sockets.AddressFamily.InterNetworkV6' to force to IPv6.\nOr use 'System.Net.Sockets.AddressFamily.Unknown' to attempt both IPv6 and IPv4." }, "HostName": { "type": "string", - "description": "Retrieve or set the hostname of this T:RabbitMQ.Client.AmqpTcpEndpoint." + "description": "Retrieve or set the hostname of this 'RabbitMQ.Client.AmqpTcpEndpoint'." }, "Port": { "type": "integer", @@ -198,7 +198,7 @@ "Tls12", "Tls13" ], - "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using F:System.Security.Authentication.SslProtocols.None .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." + "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using 'System.Security.Authentication.SslProtocols.None' .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." } }, "description": "Retrieve the TLS options for this AmqpTcpEndpoint. If not set, null is returned." @@ -230,7 +230,7 @@ }, "Port": { "type": "integer", - "description": "The port to connect on. F:RabbitMQ.Client.AmqpTcpEndpoint.UseDefaultPort indicates the default for the protocol should be used." + "description": "The port to connect on. 'RabbitMQ.Client.AmqpTcpEndpoint.UseDefaultPort' indicates the default for the protocol should be used." }, "RequestedChannelMax": { "type": "integer", @@ -303,7 +303,7 @@ "Tls12", "Tls13" ], - "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using F:System.Security.Authentication.SslProtocols.None .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." + "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using 'System.Security.Authentication.SslProtocols.None' .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." } }, "description": "TLS options setting." @@ -326,7 +326,7 @@ "description": "Virtual host to access during this connection." } }, - "description": "Main entry point to the RabbitMQ .NET AMQP client\nAPI. Constructs T:RabbitMQ.Client.IConnection instances." + "description": "Main entry point to the RabbitMQ .NET AMQP client\nAPI. Constructs 'RabbitMQ.Client.IConnection' instances." }, "ConnectionString": { "type": "string", diff --git a/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json b/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json index 78b08a0fc4..7b1b6316ec 100644 --- a/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json +++ b/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json @@ -38,7 +38,7 @@ "properties": { "UseImplicitAutoPattern": { "type": "boolean", - "description": "Indicates whether channels should use F:StackExchange.Redis.RedisChannel.PatternMode.Auto when no T:StackExchange.Redis.RedisChannel.PatternMode is specified; this is enabled by default, but can be disabled to avoid unexpected wildcard scenarios." + "description": "Indicates whether channels should use 'StackExchange.Redis.RedisChannel.PatternMode.Auto' when no 'StackExchange.Redis.RedisChannel.PatternMode' is specified; this is enabled by default, but can be disabled to avoid unexpected wildcard scenarios." } }, "description": "Automatically encodes and decodes channels." @@ -69,7 +69,7 @@ }, "DefaultDatabase": { "type": "integer", - "description": "Specifies the default database to be used when calling M:StackExchange.Redis.ConnectionMultiplexer.GetDatabase(System.Int32,System.Object) without any parameters." + "description": "Specifies the default database to be used when calling 'StackExchange.Redis.ConnectionMultiplexer.GetDatabase(System.Int32,System.Object)' without any parameters." }, "DefaultVersion": { "type": "string", @@ -113,7 +113,7 @@ "Twemproxy", "Envoyproxy" ], - "description": "Type of proxy to use (if any); for example F:StackExchange.Redis.Proxy.Twemproxy." + "description": "Type of proxy to use (if any); for example 'StackExchange.Redis.Proxy.Twemproxy'." }, "ResolveDns": { "type": "boolean", diff --git a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs index a3158a86f9..6741bde280 100644 --- a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs +++ b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Globalization; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; @@ -25,6 +26,9 @@ internal sealed partial class ConfigSchemaEmitter(SchemaGenerationSpec spec, Com [GeneratedRegex(@"( *)\r?\n( *)")] private static partial Regex Indentation(); + [GeneratedRegex(@"(?[A-Z]):(?[a-zA-Z0-9.]+)")] + private static partial Regex TypeOrPropertyPrefix(); + public string GenerateSchema() { var root = new JsonObject(); @@ -240,6 +244,7 @@ private static void GenerateDocCommentsProperties(JsonObject propertyNode, strin foreach (var node in StripXmlElements(summary)) { var value = node.ToString().Trim(); + value = ReplacePropertyOrTypeNamespacePrefixIfNecessary(value); AppendSpaceIfNecessary(builder, value); AppendUnindentedValue(builder, value); } @@ -329,6 +334,14 @@ private static void AppendSpaceIfNecessary(StringBuilder builder, string value) } } + internal static string ReplacePropertyOrTypeNamespacePrefixIfNecessary(string value) + { + const string quotedName = "'{0}'"; + + return TypeOrPropertyPrefix().IsMatch(value) ? + string.Format(CultureInfo.InvariantCulture, quotedName, value[2..]) : value; + } + internal static void AppendUnindentedValue(StringBuilder builder, string value) { var index = 0; diff --git a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs index a3d33716a7..d3230bba57 100644 --- a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs +++ b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs @@ -37,4 +37,19 @@ public void ShouldRemoveIndentation(string value, string expected) Assert.Equal(expected, builder.ToString()); } + + [Theory] + [InlineData("", "")] + [InlineData("no namespace", "no namespace")] + [InlineData("no-namespace", "no-namespace")] + [InlineData("T:System.Uri", "'System.Uri'")] + [InlineData("T:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier", "'Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier'")] + [InlineData("P:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri", "'Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri'")] + [InlineData("https://aka.ms/azsdk/blog/vault-uri", "https://aka.ms/azsdk/blog/vault-uri")] + public void ShouldTrimAndSanitize(string input, string expected) + { + var result = ConfigSchemaEmitter.ReplacePropertyOrTypeNamespacePrefixIfNecessary(input); + + Assert.Equal(expected, result); + } } From 57105e85f63cd72d463e4735fc5b4f349933f216 Mon Sep 17 00:00:00 2001 From: Kia Raad Date: Thu, 21 Dec 2023 16:25:48 +0330 Subject: [PATCH 2/7] Rename method and regex capture group from namespace to member type --- .../ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs | 6 +++--- tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs index 6741bde280..32c383fd19 100644 --- a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs +++ b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs @@ -26,7 +26,7 @@ internal sealed partial class ConfigSchemaEmitter(SchemaGenerationSpec spec, Com [GeneratedRegex(@"( *)\r?\n( *)")] private static partial Regex Indentation(); - [GeneratedRegex(@"(?[A-Z]):(?[a-zA-Z0-9.]+)")] + [GeneratedRegex(@"(?[A-Z]):(?[a-zA-Z0-9.]+)")] private static partial Regex TypeOrPropertyPrefix(); public string GenerateSchema() @@ -244,7 +244,7 @@ private static void GenerateDocCommentsProperties(JsonObject propertyNode, strin foreach (var node in StripXmlElements(summary)) { var value = node.ToString().Trim(); - value = ReplacePropertyOrTypeNamespacePrefixIfNecessary(value); + value = ReplaceMemberTypePrefixIfNecessary(value); AppendSpaceIfNecessary(builder, value); AppendUnindentedValue(builder, value); } @@ -334,7 +334,7 @@ private static void AppendSpaceIfNecessary(StringBuilder builder, string value) } } - internal static string ReplacePropertyOrTypeNamespacePrefixIfNecessary(string value) + internal static string ReplaceMemberTypePrefixIfNecessary(string value) { const string quotedName = "'{0}'"; diff --git a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs index d3230bba57..7e7dbe874a 100644 --- a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs +++ b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs @@ -48,7 +48,7 @@ public void ShouldRemoveIndentation(string value, string expected) [InlineData("https://aka.ms/azsdk/blog/vault-uri", "https://aka.ms/azsdk/blog/vault-uri")] public void ShouldTrimAndSanitize(string input, string expected) { - var result = ConfigSchemaEmitter.ReplacePropertyOrTypeNamespacePrefixIfNecessary(input); + var result = ConfigSchemaEmitter.ReplaceMemberTypePrefixIfNecessary(input); Assert.Equal(expected, result); } From a21f36a08fd673d935690e8e66a0dacc40c21fb3 Mon Sep 17 00:00:00 2001 From: Kia Raad Date: Fri, 22 Dec 2023 16:02:32 +0330 Subject: [PATCH 3/7] Update XmlDocument member type regex and corresponding tests# --- .../ConfigSchemaEmitter.cs | 8 ++-- .../GeneratorTests.cs | 39 ++++++++++++++----- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs index 32c383fd19..5a7fd55995 100644 --- a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs +++ b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs @@ -26,8 +26,8 @@ internal sealed partial class ConfigSchemaEmitter(SchemaGenerationSpec spec, Com [GeneratedRegex(@"( *)\r?\n( *)")] private static partial Regex Indentation(); - [GeneratedRegex(@"(?[A-Z]):(?[a-zA-Z0-9.]+)")] - private static partial Regex TypeOrPropertyPrefix(); + [GeneratedRegex(@"^(?[A-Z]):(?[a-zA-Z0-9.`_<>]+)$")] + internal static partial Regex XmlDocumentMemberType(); public string GenerateSchema() { @@ -334,11 +334,11 @@ private static void AppendSpaceIfNecessary(StringBuilder builder, string value) } } - internal static string ReplaceMemberTypePrefixIfNecessary(string value) + private static string ReplaceMemberTypePrefixIfNecessary(string value) { const string quotedName = "'{0}'"; - return TypeOrPropertyPrefix().IsMatch(value) ? + return XmlDocumentMemberType().IsMatch(value) ? string.Format(CultureInfo.InvariantCulture, quotedName, value[2..]) : value; } diff --git a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs index 7e7dbe874a..18dc614559 100644 --- a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs +++ b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs @@ -39,17 +39,36 @@ public void ShouldRemoveIndentation(string value, string expected) } [Theory] - [InlineData("", "")] - [InlineData("no namespace", "no namespace")] - [InlineData("no-namespace", "no-namespace")] - [InlineData("T:System.Uri", "'System.Uri'")] - [InlineData("T:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier", "'Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier'")] - [InlineData("P:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri", "'Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri'")] - [InlineData("https://aka.ms/azsdk/blog/vault-uri", "https://aka.ms/azsdk/blog/vault-uri")] - public void ShouldTrimAndSanitize(string input, string expected) + [InlineData("T:System.Int32")] + [InlineData("T:system.int32")] + [InlineData("T:Azure.Response`1")] + [InlineData("T:azure.response`1")] + [InlineData("M:System.Module")] + [InlineData("M:system.module")] + [InlineData("M:System.Module`1")] + [InlineData("M:system.module`1")] + [InlineData("M:<>__c")] + [InlineData("M:<>__C")] + [InlineData("P:k__BackingField")] + [InlineData("P:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri")] + [InlineData("P:azure.Security.keyVault.Secrets.KeyVaultSecretIdentifier.VaultUri")] + public void MatchesXmlDocumentMemberTypePattern(string input) { - var result = ConfigSchemaEmitter.ReplaceMemberTypePrefixIfNecessary(input); + Assert.Matches(ConfigSchemaEmitter.XmlDocumentMemberType(), input); + } - Assert.Equal(expected, result); + [Theory] + [InlineData("")] + [InlineData("no namespace")] + [InlineData("no-namespace")] + [InlineData("( abcde )")] + [InlineData("TM:System.Int32")] + [InlineData("t:System.Int32")] + [InlineData("AAAAA:AAAAAA")] + [InlineData(" A:P ")] + [InlineData("https://aka.ms/azsdk/blog/vault-uri")] + public void DoesNotMatchXmlDocumentMemberTypePattern(string input) + { + Assert.DoesNotMatch(ConfigSchemaEmitter.XmlDocumentMemberType(), input); } } From 6754c5dde77ab2bb4c183746605805facb4af3bc Mon Sep 17 00:00:00 2001 From: Kia Raad Date: Fri, 22 Dec 2023 16:03:05 +0330 Subject: [PATCH 4/7] Cache and reuse JsonSerializerOptions instead of new-ing up every time. --- .../ConfigSchemaEmitter.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs index 5a7fd55995..84b0e6c707 100644 --- a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs +++ b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs @@ -18,6 +18,15 @@ namespace ConfigurationSchemaGenerator; internal sealed partial class ConfigSchemaEmitter(SchemaGenerationSpec spec, Compilation compilation) { + private static readonly JsonSerializerOptions s_serializerOptions = new() + { + WriteIndented = true, + // ensure the properties are ordered correctly + Converters = { SchemaOrderJsonNodeConverter.Instance }, + // prevent known escaped characters from being \uxxxx encoded + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + private readonly TypeIndex _typeIndex = new TypeIndex(spec.AllTypes); private readonly Compilation _compilation = compilation; private readonly Stack _visitedTypes = new(); @@ -36,15 +45,7 @@ public string GenerateSchema() root["properties"] = GenerateGraph(); root["type"] = "object"; - var options = new JsonSerializerOptions() - { - WriteIndented = true, - // ensure the properties are ordered correctly - Converters = { SchemaOrderJsonNodeConverter.Instance }, - // prevent known escaped characters from being \uxxxx encoded - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }; - return JsonSerializer.Serialize(root, options); + return JsonSerializer.Serialize(root, s_serializerOptions); } private void GenerateLogCategories(JsonObject parent) From 7bf02b65dd413e9391c4fb4c45321015c2dcb8a1 Mon Sep 17 00:00:00 2001 From: Kia Raad Date: Fri, 22 Dec 2023 16:12:57 +0330 Subject: [PATCH 5/7] Regenerate ConfigurationSchema.json files after the generator changes --- .../Aspire.Azure.Storage.Blobs/ConfigurationSchema.json | 2 +- .../Aspire.StackExchange.Redis/ConfigurationSchema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json b/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json index ab8f64a328..1e4827616b 100644 --- a/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json @@ -151,7 +151,7 @@ }, "TrimBlobNameSlashes": { "type": "boolean", - "description": "Whether to trim leading and trailing slashes on a blob name when using 'Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String)' and similar methods.\nDefaults to true for backwards compatibility." + "description": "Whether to trim leading and trailing slashes on a blob name when using M:Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String) and similar methods.\nDefaults to true for backwards compatibility." } }, "description": "Provides the client configuration options for connecting to Azure Blob\nStorage." diff --git a/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json b/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json index 7b1b6316ec..f711e0d418 100644 --- a/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json +++ b/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json @@ -69,7 +69,7 @@ }, "DefaultDatabase": { "type": "integer", - "description": "Specifies the default database to be used when calling 'StackExchange.Redis.ConnectionMultiplexer.GetDatabase(System.Int32,System.Object)' without any parameters." + "description": "Specifies the default database to be used when calling M:StackExchange.Redis.ConnectionMultiplexer.GetDatabase(System.Int32,System.Object) without any parameters." }, "DefaultVersion": { "type": "string", From 2bd9b0641c79d7e8f2e89de47e2779af3c06e87d Mon Sep 17 00:00:00 2001 From: Kia Raad Date: Sun, 24 Dec 2023 16:27:53 +0330 Subject: [PATCH 6/7] Fix typo --- .../Configuration.Binder/Parser/KnownTypeSymbols.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tools/ConfigurationSchemaGenerator/RuntimeSource/Configuration.Binder/Parser/KnownTypeSymbols.cs b/src/Tools/ConfigurationSchemaGenerator/RuntimeSource/Configuration.Binder/Parser/KnownTypeSymbols.cs index 89ff70db19..c192757315 100644 --- a/src/Tools/ConfigurationSchemaGenerator/RuntimeSource/Configuration.Binder/Parser/KnownTypeSymbols.cs +++ b/src/Tools/ConfigurationSchemaGenerator/RuntimeSource/Configuration.Binder/Parser/KnownTypeSymbols.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -83,7 +83,7 @@ public KnownTypeSymbols(CSharpCompilation compilation) Uri = compilation.GetBestTypeByMetadataName(typeof(Uri)); Version = compilation.GetBestTypeByMetadataName(typeof(Version)); - // Used to verify input configuation binding API calls. + // Used to verify input configuration binding API calls. INamedTypeSymbol? binderOptions = compilation.GetBestTypeByMetadataName("Microsoft.Extensions.Configuration.BinderOptions"); ActionOfBinderOptions = binderOptions is null ? null : compilation.GetBestTypeByMetadataName(typeof(Action<>))?.Construct(binderOptions); ConfigurationBinder = compilation.GetBestTypeByMetadataName("Microsoft.Extensions.Configuration.ConfigurationBinder"); From c95eab01fe2c133f03ca1eb28fa86a70857cce69 Mon Sep 17 00:00:00 2001 From: Kia Raad Date: Sun, 24 Dec 2023 16:29:43 +0330 Subject: [PATCH 7/7] Move config schema generation xml node formatting logic from using RegEx to parsing time in "StripXmlElements" method --- .../ConfigurationSchema.json | 2 +- .../ConfigurationSchema.json | 2 +- .../ConfigurationSchema.json | 10 +-- .../ConfigurationSchema.json | 6 +- .../ConfigSchemaEmitter.cs | 33 +++++---- .../GeneratorTests.cs | 71 ++++++++++++------- 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json b/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json index 1e4827616b..ab8f64a328 100644 --- a/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Storage.Blobs/ConfigurationSchema.json @@ -151,7 +151,7 @@ }, "TrimBlobNameSlashes": { "type": "boolean", - "description": "Whether to trim leading and trailing slashes on a blob name when using M:Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String) and similar methods.\nDefaults to true for backwards compatibility." + "description": "Whether to trim leading and trailing slashes on a blob name when using 'Azure.Storage.Blobs.BlobContainerClient.GetBlobClient(System.String)' and similar methods.\nDefaults to true for backwards compatibility." } }, "description": "Provides the client configuration options for connecting to Azure Blob\nStorage." diff --git a/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json b/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json index 88f50fb474..80f8ed4f55 100644 --- a/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json +++ b/src/Components/Aspire.Azure.Storage.Queues/ConfigurationSchema.json @@ -78,7 +78,7 @@ "None", "Base64" ], - "description": "Gets or sets a message encoding that determines how 'Azure.Storage.Queues.Models.QueueMessage.Body' is represented in HTTP requests and responses.\nThe default is 'Azure.Storage.Queues.QueueMessageEncoding.None'." + "description": "Gets or sets a message encoding that determines how 'Azure.Storage.Queues.Models.QueueMessage.Body' is represented in HTTP requests and responses.\nThe default is F:Azure.Storage.Queues.QueueMessageEncoding.None." }, "Retry": { "type": "object", diff --git a/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json b/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json index ea61b51bd1..b7a0af87f0 100644 --- a/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json +++ b/src/Components/Aspire.RabbitMQ.Client/ConfigurationSchema.json @@ -87,7 +87,7 @@ "Packet", "ControllerAreaNetwork" ], - "description": "Address family used by default.\nUse 'System.Net.Sockets.AddressFamily.InterNetwork' to force to IPv4.\nUse 'System.Net.Sockets.AddressFamily.InterNetworkV6' to force to IPv6.\nOr use 'System.Net.Sockets.AddressFamily.Unknown' to attempt both IPv6 and IPv4." + "description": "Address family used by default.\nUse F:System.Net.Sockets.AddressFamily.InterNetwork to force to IPv4.\nUse F:System.Net.Sockets.AddressFamily.InterNetworkV6 to force to IPv6.\nOr use F:System.Net.Sockets.AddressFamily.Unknown to attempt both IPv6 and IPv4." }, "DefaultAmqpUriSslProtocols": { "enum": [ @@ -145,7 +145,7 @@ "Packet", "ControllerAreaNetwork" ], - "description": "Used to force the address family of the endpoint.\nUse 'System.Net.Sockets.AddressFamily.InterNetwork' to force to IPv4.\nUse 'System.Net.Sockets.AddressFamily.InterNetworkV6' to force to IPv6.\nOr use 'System.Net.Sockets.AddressFamily.Unknown' to attempt both IPv6 and IPv4." + "description": "Used to force the address family of the endpoint.\nUse F:System.Net.Sockets.AddressFamily.InterNetwork to force to IPv4.\nUse F:System.Net.Sockets.AddressFamily.InterNetworkV6 to force to IPv6.\nOr use F:System.Net.Sockets.AddressFamily.Unknown to attempt both IPv6 and IPv4." }, "HostName": { "type": "string", @@ -198,7 +198,7 @@ "Tls12", "Tls13" ], - "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using 'System.Security.Authentication.SslProtocols.None' .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." + "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using F:System.Security.Authentication.SslProtocols.None .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." } }, "description": "Retrieve the TLS options for this AmqpTcpEndpoint. If not set, null is returned." @@ -230,7 +230,7 @@ }, "Port": { "type": "integer", - "description": "The port to connect on. 'RabbitMQ.Client.AmqpTcpEndpoint.UseDefaultPort' indicates the default for the protocol should be used." + "description": "The port to connect on. F:RabbitMQ.Client.AmqpTcpEndpoint.UseDefaultPort indicates the default for the protocol should be used." }, "RequestedChannelMax": { "type": "integer", @@ -303,7 +303,7 @@ "Tls12", "Tls13" ], - "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using 'System.Security.Authentication.SslProtocols.None' .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." + "description": "Retrieve or set the TLS protocol version.\nThe client will let the OS pick a suitable version by using F:System.Security.Authentication.SslProtocols.None .\nIf this option is disabled, e.g.see via app context, the client will attempt to fall back\nto TLSv1.2." } }, "description": "TLS options setting." diff --git a/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json b/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json index f711e0d418..2ce03a7d81 100644 --- a/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json +++ b/src/Components/Aspire.StackExchange.Redis/ConfigurationSchema.json @@ -38,7 +38,7 @@ "properties": { "UseImplicitAutoPattern": { "type": "boolean", - "description": "Indicates whether channels should use 'StackExchange.Redis.RedisChannel.PatternMode.Auto' when no 'StackExchange.Redis.RedisChannel.PatternMode' is specified; this is enabled by default, but can be disabled to avoid unexpected wildcard scenarios." + "description": "Indicates whether channels should use F:StackExchange.Redis.RedisChannel.PatternMode.Auto when no 'StackExchange.Redis.RedisChannel.PatternMode' is specified; this is enabled by default, but can be disabled to avoid unexpected wildcard scenarios." } }, "description": "Automatically encodes and decodes channels." @@ -69,7 +69,7 @@ }, "DefaultDatabase": { "type": "integer", - "description": "Specifies the default database to be used when calling M:StackExchange.Redis.ConnectionMultiplexer.GetDatabase(System.Int32,System.Object) without any parameters." + "description": "Specifies the default database to be used when calling 'StackExchange.Redis.ConnectionMultiplexer.GetDatabase(System.Int32,System.Object)' without any parameters." }, "DefaultVersion": { "type": "string", @@ -113,7 +113,7 @@ "Twemproxy", "Envoyproxy" ], - "description": "Type of proxy to use (if any); for example 'StackExchange.Redis.Proxy.Twemproxy'." + "description": "Type of proxy to use (if any); for example F:StackExchange.Redis.Proxy.Twemproxy." }, "ResolveDns": { "type": "boolean", diff --git a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs index 84b0e6c707..d08ddcf27e 100644 --- a/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs +++ b/src/Tools/ConfigurationSchemaGenerator/ConfigSchemaEmitter.cs @@ -35,9 +35,6 @@ internal sealed partial class ConfigSchemaEmitter(SchemaGenerationSpec spec, Com [GeneratedRegex(@"( *)\r?\n( *)")] private static partial Regex Indentation(); - [GeneratedRegex(@"^(?[A-Z]):(?[a-zA-Z0-9.`_<>]+)$")] - internal static partial Regex XmlDocumentMemberType(); - public string GenerateSchema() { var root = new JsonObject(); @@ -245,7 +242,6 @@ private static void GenerateDocCommentsProperties(JsonObject propertyNode, strin foreach (var node in StripXmlElements(summary)) { var value = node.ToString().Trim(); - value = ReplaceMemberTypePrefixIfNecessary(value); AppendSpaceIfNecessary(builder, value); AppendUnindentedValue(builder, value); } @@ -298,8 +294,13 @@ private static IEnumerable StripXmlElements(XContainer container) }); } - private static IEnumerable StripXmlElements(XElement element) + internal static IEnumerable StripXmlElements(XElement element) { + const string typePrefix = "T:"; + const string methodPrefix = "M:"; + const string propertyPrefix = "P:"; + const string quotedFormat = "'{0}'"; + if (element.Nodes().Any()) { return StripXmlElements((XContainer)element); @@ -309,7 +310,19 @@ private static IEnumerable StripXmlElements(XElement element) // just get the first attribute value // ex. // ex. - return [new XText(element.FirstAttribute.Value)]; + var attributeValue = element.FirstAttribute.Value; + + // format the attribute value only if its a Type, Method or Property. + // i.e., is prefixed with 'T:', 'M:', or, 'P:' in the xml. + var formattedValue = attributeValue switch + { + var s when s.StartsWith(typePrefix, StringComparison.Ordinal) => string.Format(CultureInfo.InvariantCulture, quotedFormat, s[2..]), + var s when s.StartsWith(methodPrefix, StringComparison.Ordinal) => string.Format(CultureInfo.InvariantCulture, quotedFormat, s[2..]), + var s when s.StartsWith(propertyPrefix, StringComparison.Ordinal) => string.Format(CultureInfo.InvariantCulture, quotedFormat, s[2..]), + _ => attributeValue, + }; + + return [new XText(formattedValue)]; } return Enumerable.Empty(); @@ -335,14 +348,6 @@ private static void AppendSpaceIfNecessary(StringBuilder builder, string value) } } - private static string ReplaceMemberTypePrefixIfNecessary(string value) - { - const string quotedName = "'{0}'"; - - return XmlDocumentMemberType().IsMatch(value) ? - string.Format(CultureInfo.InvariantCulture, quotedName, value[2..]) : value; - } - internal static void AppendUnindentedValue(StringBuilder builder, string value) { var index = 0; diff --git a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs index 18dc614559..bc87b404ab 100644 --- a/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs +++ b/tests/ConfigurationSchemaGenerator.Tests/GeneratorTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text; +using System.Xml; +using System.Xml.Linq; using Xunit; namespace ConfigurationSchemaGenerator.Tests; @@ -39,36 +41,53 @@ public void ShouldRemoveIndentation(string value, string expected) } [Theory] - [InlineData("T:System.Int32")] - [InlineData("T:system.int32")] - [InlineData("T:Azure.Response`1")] - [InlineData("T:azure.response`1")] - [InlineData("M:System.Module")] - [InlineData("M:system.module")] - [InlineData("M:System.Module`1")] - [InlineData("M:system.module`1")] - [InlineData("M:<>__c")] - [InlineData("M:<>__C")] - [InlineData("P:k__BackingField")] - [InlineData("P:Azure.Security.KeyVault.Secrets.KeyVaultSecretIdentifier.VaultUri")] - [InlineData("P:azure.Security.keyVault.Secrets.KeyVaultSecretIdentifier.VaultUri")] - public void MatchesXmlDocumentMemberTypePattern(string input) + [InlineData("", "'System.Uri'")] + [InlineData("", "'Azure.Core.Extensions.IAzureClientBuilder`2'")] + [InlineData("", "'Aspire.Azure.Storage.Blobs.AzureStorageBlobsSettings.ConnectionString'")] + [InlineData("", "'System.Diagnostics.Debug.Assert(bool)'")] + [InlineData("", "'System.InvalidOperationException'")] + public void StripXmlElementsShouldFormatCrefAttributes(string input, string expected) { - Assert.Matches(ConfigSchemaEmitter.XmlDocumentMemberType(), input); + var bytes = Encoding.UTF8.GetBytes(input); + using Stream stream = new MemoryStream(bytes); + using var reader = XmlReader.Create(stream); + reader.MoveToContent(); + var node = (XElement)XNode.ReadFrom(reader); + var stripedNodes = ConfigSchemaEmitter.StripXmlElements(node); + + var first = stripedNodes.First(); + Assert.Equal(expected, first.ToString().Trim()); } [Theory] - [InlineData("")] - [InlineData("no namespace")] - [InlineData("no-namespace")] - [InlineData("( abcde )")] - [InlineData("TM:System.Int32")] - [InlineData("t:System.Int32")] - [InlineData("AAAAA:AAAAAA")] - [InlineData(" A:P ")] - [InlineData("https://aka.ms/azsdk/blog/vault-uri")] - public void DoesNotMatchXmlDocumentMemberTypePattern(string input) + [InlineData("", "https://aka.ms/azsdk/blog/vault-uri")] + [InlineData("", "true")] + public void StripXmlElementsShouldNotFormatNonCrefAttributes(string input, string expected) { - Assert.DoesNotMatch(ConfigSchemaEmitter.XmlDocumentMemberType(), input); + var bytes = Encoding.UTF8.GetBytes(input); + using Stream stream = new MemoryStream(bytes); + using var reader = XmlReader.Create(stream); + reader.MoveToContent(); + var node = (XElement)XNode.ReadFrom(reader); + var stripedNodes = ConfigSchemaEmitter.StripXmlElements(node); + + var first = stripedNodes.First(); + Assert.Equal(expected, first.ToString().Trim()); + } + + [Theory] + [InlineData("A name used to retrieve the connection string from the ConnectionStrings configuration section.", "A name used to retrieve the connection string from the ConnectionStrings configuration section.")] + [InlineData("", "name")] + public void StripXmlElementsShouldNotFormatMiscAttributes(string input, string expected) + { + var bytes = Encoding.UTF8.GetBytes(input); + using Stream stream = new MemoryStream(bytes); + using var reader = XmlReader.Create(stream); + reader.MoveToContent(); + var node = (XElement)XNode.ReadFrom(reader); + var stripedNodes = ConfigSchemaEmitter.StripXmlElements(node); + + var first = stripedNodes.First(); + Assert.Equal(expected, first.ToString().Trim()); } }