public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages() { // Arrange var viewPath = "Views/Home/Index"; var generatedCodeFileName = "Generated Code"; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("view-content", viewPath)); var assemblyName = "random-assembly-name"; var diagnostics = new[] { Diagnostic.Create( GetRoslynDiagnostic("message-1"), Location.Create( viewPath, new TextSpan(10, 5), new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))), Diagnostic.Create( GetRoslynDiagnostic("message-2"), Location.Create( assemblyName, new TextSpan(1, 6), new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))), Diagnostic.Create( GetRoslynDiagnostic("message-3"), Location.Create( viewPath, new TextSpan(40, 50), new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))), }; // Act var compilationResult = CompilationFailedExceptionFactory.Create( codeDocument, "compilation-content", assemblyName, diagnostics); // Assert Assert.Collection(compilationResult.CompilationFailures, failure => { Assert.Equal(viewPath, failure.SourceFilePath); Assert.Equal("view-content", failure.SourceFileContent); Assert.Collection(failure.Messages, message => { Assert.Equal("message-1", message.Message); Assert.Equal(viewPath, message.SourceFilePath); Assert.Equal(11, message.StartLine); Assert.Equal(2, message.StartColumn); Assert.Equal(11, message.EndLine); Assert.Equal(3, message.EndColumn); }, message => { Assert.Equal("message-3", message.Message); Assert.Equal(viewPath, message.SourceFilePath); Assert.Equal(31, message.StartLine); Assert.Equal(6, message.StartColumn); Assert.Equal(41, message.EndLine); Assert.Equal(13, message.EndColumn); }); }, failure => { Assert.Equal(generatedCodeFileName, failure.SourceFilePath); Assert.Equal("compilation-content", failure.SourceFileContent); Assert.Collection(failure.Messages, message => { Assert.Equal("message-2", message.Message); Assert.Equal(assemblyName, message.SourceFilePath); Assert.Equal(2, message.StartLine); Assert.Equal(3, message.StartColumn); Assert.Equal(4, message.EndLine); Assert.Equal(5, message.EndColumn); }); }); }
public void Execute_AddsRazorPagettribute_ToPage() { // Arrange var expectedAttribute = "[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(@\"/Views/Index.cshtml\", typeof(SomeNamespace.SomeName), null)]"; var irDocument = new DocumentIntermediateNode { DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind, Options = RazorCodeGenerationOptions.CreateDefault(), }; var builder = IntermediateNodeBuilder.Create(irDocument); var pageDirective = new DirectiveIntermediateNode { Directive = PageDirective.Directive, }; builder.Add(pageDirective); var @namespace = new NamespaceDeclarationIntermediateNode { Content = "SomeNamespace", Annotations = { [CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace }, }; builder.Push(@namespace); var @class = new ClassDeclarationIntermediateNode { ClassName = "SomeName", Annotations = { [CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass, }, }; builder.Add(@class); var pass = new AssemblyAttributeInjectionPass { Engine = RazorEngine.Create(), }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "/Views/Index.cshtml")); var document = RazorCodeDocument.Create(source); // Act pass.Execute(document, irDocument); // Assert Assert.Collection(irDocument.Children, node => Assert.Same(pageDirective, node), node => { var csharpCode = Assert.IsType <CSharpCodeIntermediateNode>(node); var token = Assert.IsType <IntermediateToken>(Assert.Single(csharpCode.Children)); Assert.Equal(TokenKind.CSharp, token.Kind); Assert.Equal(expectedAttribute, token.Content); }, node => Assert.Same(@namespace, node)); }
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); } } }
public void GetCompilationFailedResult_GroupsMessages() { // Arrange var viewPath = "views/index.razor"; var viewImportsPath = "views/global.import.cshtml"; var codeDocument = RazorCodeDocument.Create( Create(viewPath, "View Content"), new[] { Create(viewImportsPath, "Global Import Content") }); var diagnostics = new[] { GetRazorDiagnostic("message-1", new SourceLocation(1, 2, 17), length: 1), GetRazorDiagnostic("message-2", new SourceLocation(viewPath, 1, 4, 6), length: 7), GetRazorDiagnostic("message-3", SourceLocation.Undefined, length: -1), GetRazorDiagnostic("message-4", new SourceLocation(viewImportsPath, 1, 3, 8), length: 4), }; var fileProvider = new TestFileProvider(); // Act var result = CompilationFailedExceptionFactory.Create(codeDocument, diagnostics); // Assert Assert.Collection(result.CompilationFailures, failure => { Assert.Equal(viewPath, failure.SourceFilePath); Assert.Equal("View Content", failure.SourceFileContent); Assert.Collection(failure.Messages, message => { Assert.Equal(diagnostics[0].GetMessage(), message.Message); Assert.Equal(viewPath, message.SourceFilePath); Assert.Equal(3, message.StartLine); Assert.Equal(17, message.StartColumn); Assert.Equal(3, message.EndLine); Assert.Equal(18, message.EndColumn); }, message => { Assert.Equal(diagnostics[1].GetMessage(), message.Message); Assert.Equal(viewPath, message.SourceFilePath); Assert.Equal(5, message.StartLine); Assert.Equal(6, message.StartColumn); Assert.Equal(5, message.EndLine); Assert.Equal(13, message.EndColumn); }, message => { Assert.Equal(diagnostics[2].GetMessage(), message.Message); Assert.Equal(viewPath, message.SourceFilePath); Assert.Equal(0, message.StartLine); Assert.Equal(-1, message.StartColumn); Assert.Equal(0, message.EndLine); Assert.Equal(-2, message.EndColumn); }); }, failure => { Assert.Equal(viewImportsPath, failure.SourceFilePath); Assert.Equal("Global Import Content", failure.SourceFileContent); Assert.Collection(failure.Messages, message => { Assert.Equal(diagnostics[3].GetMessage(), message.Message); Assert.Equal(viewImportsPath, message.SourceFilePath); Assert.Equal(4, message.StartLine); Assert.Equal(8, message.StartColumn); Assert.Equal(4, message.EndLine); Assert.Equal(12, message.EndColumn); }); }); }
private RazorCodeDocument CreateDocument(string content) { var source = RazorSourceDocument.Create(content, "test.cshtml"); return(RazorCodeDocument.Create(source)); }
private static Type CreateGeneratorType(Type _) { var name = typeof(T).FullName; var metadataReferences = GetMetadataReferences(); RazorSourceDocument document; using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream($"{name}.razor")) { if (stream == null) { throw new Exception($"Could not find embedded resource {name}.razor"); } using (var reader = new StreamReader(stream)) { document = RazorSourceDocument.Create(reader.ReadToEnd(), $"{name}.razor"); } } #pragma warning disable CS0618 //Create and Register are marked as obsolete but there aren't alternative available var engine = RazorEngine.Create(b => { FunctionsDirective.Register(b); InheritsDirective.Register(b); #pragma warning restore CS0618 }); RazorCodeDocument codeDocument = RazorCodeDocument.Create(document); engine.Process(codeDocument); string code; using (var srcFileWriter = new StringWriter()) { code = codeDocument.GetCSharpDocument().GeneratedCode; } SourceText sourceText = SourceText.From(code, Encoding.UTF8); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceText, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest)); CSharpCompilationOptions compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithSpecificDiagnosticOptions(new Dictionary <string, ReportDiagnostic> { // Binding redirects ["CS1701"] = ReportDiagnostic.Suppress, ["CS1702"] = ReportDiagnostic.Suppress, ["CS1705"] = ReportDiagnostic.Suppress, ["CS8019"] = ReportDiagnostic.Suppress }) .WithUsings("System"); CSharpCompilation compilation = CSharpCompilation.Create(typeof(T).FullName, new List <SyntaxTree> { syntaxTree }, metadataReferences, compilationOptions); Assembly assembly; EmitOptions emitOptions = new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb); using (MemoryStream assemblyStream = new MemoryStream()) { using (MemoryStream pdbStream = new MemoryStream()) { var emitResult = compilation.Emit( assemblyStream, pdbStream, options: emitOptions); if (!emitResult.Success) { throw new Exception("Compilation error: " + string.Join("; ", emitResult.Diagnostics.Select(d => d.ToString()))); } assemblyStream.Seek(0, SeekOrigin.Begin); pdbStream.Seek(0, SeekOrigin.Begin); assembly = Assembly.Load(assemblyStream.ToArray(), pdbStream.ToArray()); } } var generatorType = assembly.GetTypes().Where(type => type.IsSubclassOf(typeof(T))).Single(); return(generatorType); }
static RazorCodeDocument CreateCodeDocument(string rootDir, string sourceFileName) { string detectedLayout = null; string detectedTagName = null; string detectedModel = null; bool detectedPage = false; List <string> detectedPageGroup = null; using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms)) { var filesToIncludeInOrder = ViewImportsFromRootToSameDir(rootDir, sourceFileName) .Concat(new[] { sourceFileName }); var sourceLines = filesToIncludeInOrder.SelectMany(file => File.ReadAllLines(file)).ToList(); string lastInheritsLine = null; var usingNamespaces = new List <string>(); foreach (var line in sourceLines) { const string inheritsLinePrefix = "@inherits "; if (line.StartsWith(inheritsLinePrefix)) { lastInheritsLine = line.Substring(inheritsLinePrefix.Length).Replace("<TModel>", string.Empty); continue; } const string layoutLinePrefix = "@layout "; if (line.StartsWith(layoutLinePrefix)) { detectedLayout = line.Substring(layoutLinePrefix.Length); continue; } const string usingLinePrefix = "@using "; if (line.StartsWith(usingLinePrefix)) { usingNamespaces.Add(line.Substring(usingLinePrefix.Length)); continue; } const string modelLinePrefix = "@model "; if (line.StartsWith(modelLinePrefix)) { detectedModel = line.Substring(modelLinePrefix.Length); continue; } // The @page directive is only used to generate the page models. // Currently, blazor assumes that all razor components are pages. const string pageLinePrefix = "@page"; if (line.StartsWith(pageLinePrefix)) { detectedPage = true; var parameters = new Regex("^\\s*{\\s*([^}]+)}\\s*"); var matches = parameters.Matches(line.Substring(pageLinePrefix.Length)); if (matches.Count > 0) { detectedPageGroup = new List <string>(); foreach (Match match in matches) { var collection = match.Groups; detectedPageGroup.Add(collection[0].Value); } } continue; } var tagNameRegex = new Regex("^\\s*\\@TagName\\(\\s*\\\"([^\\\"]+)\\\"\\s*\\)"); var tagNameMatch = tagNameRegex.Match(line); if (tagNameMatch.Success) { detectedTagName = tagNameMatch.Groups[1].Value; continue; } sw.WriteLine(line); } sw.Flush(); ms.Position = 0; var sourceDoc = RazorSourceDocument.ReadFrom(ms, sourceFileName); var codeDoc = RazorCodeDocument.Create(sourceDoc); codeDoc.Items["DetectedLayout"] = detectedLayout; codeDoc.Items["DetectedTagName"] = detectedTagName; codeDoc.Items["DetectedModel"] = detectedModel; codeDoc.Items["DetectedBaseClass"] = lastInheritsLine; codeDoc.Items["UsingNamespaces"] = usingNamespaces; codeDoc.Items["DetectedPage"] = detectedPage; codeDoc.Items["DetectedPageMatches"] = detectedPageGroup; return(codeDoc); } } }
public async Task <TemplateResult> RunTemplateAsync(string content, dynamic templateModel) { var razorEngine = RazorEngine.Create((builder) => { RazorExtensions.Register(builder); }); // Don't care about the RazorProject as we already have the content of the .cshtml file // and don't need to deal with imports. var razorProject = RazorProject.Create(Directory.GetCurrentDirectory()); var razorTemplateEngine = new RazorTemplateEngine(razorEngine, razorProject); var imports = new RazorSourceDocument[] { RazorSourceDocument.Create(@" @using System @using System.Threading.Tasks ", fileName: null) }; var razorDocument = RazorCodeDocument.Create(RazorSourceDocument.Create(content, "Template"), imports); var generatorResults = razorTemplateEngine.GenerateCode(razorDocument); if (generatorResults.Diagnostics.Any()) { var messages = generatorResults.Diagnostics.Select(d => d.GetMessage()); return(new TemplateResult() { GeneratedText = string.Empty, ProcessingException = new TemplateProcessingException(messages, generatorResults.GeneratedCode) }); } var templateResult = _compilationService.Compile(generatorResults.GeneratedCode); if (templateResult.Messages.Any()) { return(new TemplateResult() { GeneratedText = string.Empty, ProcessingException = new TemplateProcessingException(templateResult.Messages, generatorResults.GeneratedCode) }); } var compiledObject = Activator.CreateInstance(templateResult.CompiledType); var razorTemplate = compiledObject as RazorTemplateBase; string result = String.Empty; if (razorTemplate != null) { razorTemplate.Model = templateModel; //ToDo: If there are errors executing the code, they are missed here. result = await razorTemplate.ExecuteTemplate(); } return(new TemplateResult() { GeneratedText = result, ProcessingException = null }); }
public void Execute_HasRequiredInfo_AndImport_AddsItemAndSourceChecksum() { // Arrange var engine = CreateEngine(); var pass = new MetadataAttributePass() { Engine = engine, }; var sourceDocument = TestRazorSourceDocument.Create("", new RazorSourceDocumentProperties(null, "Foo\\Bar.cshtml")); var import = TestRazorSourceDocument.Create("@using System", new RazorSourceDocumentProperties(null, "Foo\\Import.cshtml")); var codeDocument = RazorCodeDocument.Create(sourceDocument, new[] { import, }); var irDocument = new DocumentIntermediateNode() { DocumentKind = "test", Options = RazorCodeGenerationOptions.Create((o) => { }), }; var builder = IntermediateNodeBuilder.Create(irDocument); var @namespace = new NamespaceDeclarationIntermediateNode { Annotations = { [CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace, }, Content = "Some.Namespace" }; builder.Push(@namespace); var @class = new ClassDeclarationIntermediateNode { Annotations = { [CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass, }, ClassName = "Test", }; builder.Add(@class); // Act pass.Execute(codeDocument, irDocument); // Assert Assert.Equal(2, irDocument.Children.Count); var item = Assert.IsType <RazorCompiledItemAttributeIntermediateNode>(irDocument.Children[0]); Assert.Equal("/Foo/Bar.cshtml", item.Identifier); Assert.Equal("test", item.Kind); Assert.Equal("Some.Namespace.Test", item.TypeName); Assert.Equal(3, @namespace.Children.Count); var checksum = Assert.IsType <RazorSourceChecksumAttributeIntermediateNode>(@namespace.Children[0]); Assert.NotNull(checksum.Checksum); // Not verifying the checksum here Assert.Equal("SHA1", checksum.ChecksumAlgorithm); Assert.Equal("/Foo/Bar.cshtml", checksum.Identifier); checksum = Assert.IsType <RazorSourceChecksumAttributeIntermediateNode>(@namespace.Children[1]); Assert.NotNull(checksum.Checksum); // Not verifying the checksum here Assert.Equal("SHA1", checksum.ChecksumAlgorithm); Assert.Equal("/Foo/Import.cshtml", checksum.Identifier); }
static RazorCodeDocument CreateCodeDocument(string rootDir, string sourceFileName) { string detectedLayout = null; string detectedTagName = null; using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms)) { var filesToIncludeInOrder = ViewImportsFromRootToSameDir(rootDir, sourceFileName) .Concat(new[] { sourceFileName }); var sourceLines = filesToIncludeInOrder.SelectMany(file => File.ReadAllLines(file)).ToList(); string lastInheritsLine = null; var usingNamespaces = new List <string>(); foreach (var line in sourceLines) { const string inheritsLinePrefix = "@inherits "; if (line.StartsWith(inheritsLinePrefix)) { lastInheritsLine = line.Substring(inheritsLinePrefix.Length).Replace("<TModel>", string.Empty); continue; } const string layoutLinePrefix = "@layout "; if (line.StartsWith(layoutLinePrefix)) { detectedLayout = line.Substring(layoutLinePrefix.Length); continue; } const string usingLinePrefix = "@using "; if (line.StartsWith(usingLinePrefix)) { usingNamespaces.Add(line.Substring(usingLinePrefix.Length)); continue; } var tagNameRegex = new Regex("^\\s*\\@TagName\\(\\s*\\\"([^\\\"]+)\\\"\\s*\\)"); var tagNameMatch = tagNameRegex.Match(line); if (tagNameMatch.Success) { detectedTagName = tagNameMatch.Groups[1].Value; continue; } sw.WriteLine(line); } sw.Flush(); ms.Position = 0; var sourceDoc = RazorSourceDocument.ReadFrom(ms, sourceFileName); var codeDoc = RazorCodeDocument.Create(sourceDoc); codeDoc.Items["DetectedLayout"] = detectedLayout; codeDoc.Items["DetectedTagName"] = detectedTagName; codeDoc.Items["DetectedBaseClass"] = lastInheritsLine; codeDoc.Items["UsingNamespaces"] = usingNamespaces; return(codeDoc); } } }
private string GetGeneratorResult(IEnumerable <string> namespaces, TypeContext context) { #pragma warning disable 612, 618 // HERE is where we create our razor engine var razorEngine = RazorEngine.Create(builder => { builder .SetNamespace(DynamicTemplateNamespace) //.SetBaseType("Microsoft.Extensions.RazorViews.BaseView") .SetBaseType(BuildTypeName(context.TemplateType, context.ModelType)) .ConfigureClass((document, @class) => { @class.ClassName = context.ClassName; //if (!str ing.IsNullOrWhiteSpace(document.Source.FilePath)) //{ // @class.ClassName = Path.GetFileNameWithoutExtension(document.Source.FilePath); //} @class.Modifiers.Clear(); @class.Modifiers.Add("internal"); }); SectionDirective.Register(builder); builder.Features.Add(new SuppressChecksumOptionsFeature()); }); string importString = @" @using System @using System.Threading.Tasks "; importString += String.Join("\r\n", namespaces.Select(n => "@using " + n.Trim())) + "\r\n"; using (var reader = context.TemplateContent.GetTemplateReader()) { string path = null; if (string.IsNullOrWhiteSpace(context.TemplateContent.TemplateFile)) { path = Directory.GetCurrentDirectory(); } else { path = Path.GetDirectoryName(context.TemplateContent.TemplateFile); } var razorProject = RazorProjectFileSystem.Create(path); var templateEngine = new RazorTemplateEngine(razorEngine, razorProject); templateEngine.Options.DefaultImports = RazorSourceDocument.Create(importString, fileName: null); RazorPageGeneratorResult result; if (string.IsNullOrWhiteSpace(context.TemplateContent.TemplateFile)) { var item = RazorSourceDocument.Create(context.TemplateContent.Template, string.Empty); var imports = new List <RazorSourceDocument>(); imports.Add(templateEngine.Options.DefaultImports); var doc = RazorCodeDocument.Create(item, imports); result = GenerateCodeFile(templateEngine, doc); } else { var item = razorProject.GetItem(context.TemplateContent.TemplateFile); result = GenerateCodeFile(templateEngine, item); } return(InspectSource(result, context)); } }