| File: Emitters\ValidationsGenerator.InfoClasses.Emitter.cs | Web Access |
| Project: src\aspnetcore\src\Validation\gen\Microsoft.Extensions.Validation.ValidationsGenerator.csproj (Microsoft.Extensions.Validation.ValidationsGenerator) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; using System.Text; namespace Microsoft.Extensions.Validation; public sealed partial class ValidationsGenerator { // Emitted in this order so base classes precede derived ones. The order is not required by the // C# compiler, but keeps the generated output readable. private static readonly string[] s_infoClassTemplates = [ "DisplayNameInfo.cs", "ValidatableInfo.cs", "ValidatableTypeInfo.cs", "ValidatablePropertyInfo.cs", "ValidatableParameterInfo.cs", "RuntimeValidatableParameterInfoResolver.cs", ]; private static readonly Lazy<string> s_infoClasses = new(BuildInfoClasses); /// <summary> /// Emits the <c>DisplayNameInfo</c> and <c>ValidatableInfo</c> family (and the runtime parameter /// resolver) as file-local class bodies so they no longer need to ship from the /// Microsoft.Extensions.Validation assembly. The bodies are emitted directly inside the existing /// <c>Microsoft.Extensions.Validation.Generated</c> namespace block, alongside the generated /// resolver. Every type reference is fully qualified with <c>global::</c> so the emitted code needs /// no <c>using</c> directives. /// </summary> internal static string EmitInfoClasses() => s_infoClasses.Value; private static string BuildInfoClasses() { var assembly = typeof(ValidationsGenerator).Assembly; var resourceNames = assembly.GetManifestResourceNames(); var sb = new StringBuilder(); foreach (var template in s_infoClassTemplates) { var resourceName = Array.Find(resourceNames, n => n.EndsWith("." + template, StringComparison.Ordinal)) ?? throw new InvalidOperationException($"Embedded template '{template}' was not found in the generator assembly."); using var stream = assembly.GetManifestResourceStream(resourceName)!; using var reader = new StreamReader(stream, Encoding.UTF8); var body = reader.ReadToEnd(); foreach (var line in body.Replace("\r\n", "\n").Split('\n')) { if (line.Length == 0) { sb.AppendLine(); } else { sb.Append(" ").AppendLine(line); } } sb.AppendLine(); } // Trim the trailing newline so the emitted classes sit flush before the enclosing // namespace's closing brace in the main template. return sb.ToString().TrimEnd('\r', '\n'); } }