static IList <SyntaxTree> GetSyntaxTrees(RazorEngine engine, string rootDir, string[] filenames) { var codeDocs = GetCodeDocuments(rootDir, filenames); var tagNamesToSourceFiles = codeDocs .Where(cd => !string.IsNullOrEmpty(cd.Items["DetectedTagName"] as string)) .ToDictionary( cd => cd.Items["DetectedTagName"] as string, cd => "./" + MakeRelativePath(rootDir, cd.Source.FileName).Replace('\\', '/')); foreach (var codeDoc in codeDocs) { codeDoc.Items["tagNamesToSourceFiles"] = tagNamesToSourceFiles; engine.Process(codeDoc); } return(codeDocs.Select(codeDoc => { var csharpDocument = codeDoc.GetCSharpDocument(); var generatedCode = csharpDocument.GeneratedCode; // If there's a better way to do this, it's not clear what it is. Don't see any public extension points // for this. generatedCode = "using System;using System.Collections.Generic;using System.Linq;using Blazor.Http;using Blazor.Util;using System.Threading.Tasks;\n" + generatedCode; generatedCode = generatedCode.Replace( "public async override global::System.Threading.Tasks.Task ExecuteAsync()", "protected override void RenderVirtualDom()"); Log(generatedCode); var syntaxTree = CSharpSyntaxTree.ParseText(generatedCode); return syntaxTree; }).ToList()); }
static IList <SyntaxTree> GetSyntaxTrees(RazorEngine engine, string rootDir, string[] filenames) { var codeDocs = GetCodeDocuments(rootDir, filenames); var tagNamesToSourceFiles = codeDocs .Where(cd => !string.IsNullOrEmpty(cd.Items["DetectedTagName"] as string)) .ToDictionary( cd => cd.Items["DetectedTagName"] as string, cd => "./" + MakeRelativePath(rootDir, cd.Source.FileName).Replace('\\', '/')); foreach (var codeDoc in codeDocs) { codeDoc.Items["tagNamesToSourceFiles"] = tagNamesToSourceFiles; engine.Process(codeDoc); } return(codeDocs.Select(codeDoc => { var csharpDocument = codeDoc.GetCSharpDocument(); var generatedCode = csharpDocument.GeneratedCode; var usingNamespaces = (IEnumerable <string>)codeDoc.Items["UsingNamespaces"]; var allNamespaces = new List <string> { "System", "System.Collections.Generic", "System.Linq", "System.Net.Http", "System.Threading.Tasks", "Blazor.Util", }; allNamespaces.AddRange(usingNamespaces); // If there's a better way to do this, it's not clear what it is. Don't see any public extension points // for this. generatedCode = string.Join(string.Empty, allNamespaces.Select(ns => $"using {ns};{Environment.NewLine}")) + generatedCode; generatedCode = generatedCode.Replace( "public async override global::System.Threading.Tasks.Task ExecuteAsync()", "protected override void RenderVirtualDom()"); if ((bool)codeDoc.Items["DetectedPage"]) { if (codeDoc.Source.FileName.Contains("Validation")) { // TODO: very very temporary. Need to make this dynamic. generatedCode = generatedCode.Replace( "protected override void RenderVirtualDom()", ValidationHack.GetValidationStuffToAppend() + "protected override void RenderVirtualDom()"); generatedCode = @"using System.Reflection; using System.ComponentModel.DataAnnotations; " + generatedCode; } } Log(generatedCode); var syntaxTree = CSharpSyntaxTree.ParseText(generatedCode); return syntaxTree; }).ToList()); }
protected virtual Type Load(RazorSourceDocument source, string relativePath) { var document = _engine.CreateCodeDocument(source); var parsed = RazorParser.Parse(source); document.SetSyntaxTree(RazorParser.Parse(source)); foreach (var error in parsed.Diagnostics) { document.ErrorSink.OnError(error); } AddVirtualDocuments(document, relativePath); var @namespace = GetNamespace(relativePath); var @class = "Generated_" + Path.GetFileNameWithoutExtension(Path.GetFileName(relativePath)); document.WithClassName(@namespace, @class); _engine.Process(document); if (document.ErrorSink.Errors.Any()) { throw CreateException(document); } var compilation = CreateCompilation(@class, @namespace, relativePath, document.GetGeneratedCSharpDocument().GeneratedCode); var text = compilation.SyntaxTrees[0].ToString(); using (var pe = new MemoryStream()) { using (var pdb = new MemoryStream()) { var emitResult = compilation.Emit( peStream: pe, pdbStream: pdb, options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb)); if (!emitResult.Success) { throw CreateException(document, relativePath, text, compilation.AssemblyName, emitResult.Diagnostics); } pe.Seek(0, SeekOrigin.Begin); pdb.Seek(0, SeekOrigin.Begin); var assembly = LoadStream(pe, pdb); var type = assembly.GetExportedTypes().FirstOrDefault(a => !a.IsNested); return(type); } } }
public void Process(RazorCodeDocument document) => _engine.Process(document);
protected void Generate() { Setup(); var stringBuilder = new StringBuilder(); stringBuilder.Append(@"namespace Razor.Orm.Template { internal static class GeneratedTemplateFactory {"); foreach (var item in assembly.GetManifestResourceNames()) { var name = item.Replace('.', '_'); RazorSourceDocument razorSourceDocument = null; var stream = new MemoryStream(); assembly.GetManifestResourceStream(item).CopyTo(stream); using (stream) using (var writer = new StreamWriter(stream, Encoding.UTF8)) { writer.WriteLine("@using System"); writer.WriteLine("@using System"); writer.WriteLine("@using System.Collections.Generic"); writer.WriteLine("@using System.Linq"); writer.WriteLine("@using System.Threading.Tasks"); writer.Flush(); stream.Position = 0; razorSourceDocument = RazorSourceDocument.ReadFrom(stream, name, Encoding.UTF8); } var razorCodeDocument = RazorCodeDocument.Create(razorSourceDocument); engine.Process(razorCodeDocument); var generatedCode = razorCodeDocument.GetCSharpDocument().GeneratedCode; Parse(generatedCode); stringBuilder.Append($@" private static {name}_GeneratedTemplate private_{name}_instance = new {name}_GeneratedTemplate(); internal static {name}_GeneratedTemplate {name}_Instance {{ get {{ return private_{name}_instance; }} }} "); } stringBuilder.Append(" } }"); var defaultTemplateFactoryCode = stringBuilder.ToString(); Parse(defaultTemplateFactoryCode); var references = DependencyContext.Load(Assembly.GetEntryAssembly()).CompileLibraries.SelectMany(library => library.ResolveReferencePaths()); if (!references.Any()) { throw new Exception(Labels.CantLoadMetadataReferenceException); } var metadataRerefences = new List <MetadataReference> { AssemblyMetadata.CreateFromFile(assembly.Location).GetReference() }; var libraryPaths = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var reference in references) { if (libraryPaths.Add(reference)) { using (var stream = File.OpenRead(reference)) { metadataRerefences.Add(AssemblyMetadata.Create(ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata)) .GetReference(filePath: reference)); } } } var compilation = CSharpCompilation.Create(assemblyName) .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences(metadataRerefences).AddSyntaxTrees(syntaxTrees); using (var assemblyStream = new MemoryStream()) { var result = compilation.Emit(assemblyStream); if (!result.Success) { var diagnostics = new StringBuilder(); diagnostics.AppendLine(Labels.CompileException); foreach (var diagnostic in result.Diagnostics.Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error)) { var lineSpan = diagnostic.Location.SourceTree.GetMappedLineSpan(diagnostic.Location.SourceSpan); diagnostics.AppendLine($"- ({lineSpan.StartLinePosition.Line}:{lineSpan.StartLinePosition.Character}) {diagnostic.GetMessage()}"); } throw new Exception(diagnostics.ToString()); } assemblyStream.Seek(0, SeekOrigin.Begin); var generatedAssembly = AssemblyLoadContext.Default.LoadFromStream(assemblyStream); foreach (var item in generatedAssembly.GetExportedTypes()) { GeneratedDao(types.First(e => e.IsAssignableFrom(item)), item); } } }