private static void AddInstrumentation(InstrumentationItem item) { var beginContextMethodName = "BeginContext"; // ORIGINAL: BeginContextMethodName var endContextMethodName = "EndContext"; // ORIGINAL: EndContextMethodName var beginNode = new CSharpCodeIntermediateNode(); beginNode.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = string.Format( CultureInfo.InvariantCulture, "{0}({1}, {2}, {3});", beginContextMethodName, item.Source.AbsoluteIndex.ToString(CultureInfo.InvariantCulture), item.Source.Length.ToString(CultureInfo.InvariantCulture), item.IsLiteral ? "true" : "false") }); var endNode = new CSharpCodeIntermediateNode(); endNode.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = string.Format(CultureInfo.InvariantCulture, "{0}();", endContextMethodName) }); var nodeIndex = item.Parent.Children.IndexOf(item.Node); item.Parent.Children.Insert(nodeIndex, beginNode); item.Parent.Children.Insert(nodeIndex + 2, endNode); }
public override void VisitCSharpStatementLiteral(CSharpStatementLiteralSyntax node) { var context = node.GetSpanContext(); if (context == null || context.ChunkGenerator is StatementChunkGenerator) { var isAttributeValue = _builder.Current is CSharpCodeAttributeValueIntermediateNode; if (!isAttributeValue) { var statementNode = new CSharpCodeIntermediateNode() { Source = BuildSourceSpanFromNode(node) }; _builder.Push(statementNode); } _builder.Add(new IntermediateToken() { Content = node.GetContent(), Kind = TokenKind.CSharp, Source = BuildSourceSpanFromNode(node), }); if (!isAttributeValue) { _builder.Pop(); } } base.VisitCSharpStatementLiteral(node); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); var @class = documentNode.FindPrimaryClass(); if (@namespace == null || @class == null) { return; } var classIndex = @namespace.Children.IndexOf(@class); foreach (var attribute in documentNode.FindDirectiveReferences(AttributeDirective.Directive)) { var token = ((DirectiveIntermediateNode)attribute.Node).Tokens.FirstOrDefault(); if (token != null) { var node = new CSharpCodeIntermediateNode { Source = token.Source }; node.Children.Add(new IntermediateToken() { Content = token.Content, Source = token.Source, Kind = TokenKind.CSharp, }); @namespace.Children.Insert(classIndex++, node); } } }
public override void VisitStatementSpan(StatementChunkGenerator chunkGenerator, Span span) { var isAttributeValue = _builder.Current is CSharpCodeAttributeValueIntermediateNode; if (!isAttributeValue) { var statementNode = new CSharpCodeIntermediateNode() { Source = BuildSourceSpanFromNode(span) }; _builder.Push(statementNode); } _builder.Add(new IntermediateToken() { Content = span.Content, Kind = TokenKind.CSharp, Source = BuildSourceSpanFromNode(span), }); if (!isAttributeValue) { _builder.Pop(); } }
public void WriteCSharpCode_WhitespaceContentWithSource_WritesContent() { // Arrange var writer = new DesignTimeNodeWriter(); var context = TestCodeRenderingContext.CreateDesignTime(); var node = new CSharpCodeIntermediateNode() { Source = new SourceSpan("test.cshtml", 0, 0, 0, 3), }; IntermediateNodeBuilder.Create(node) .Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = " " }); // Act writer.WriteCSharpCode(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @" ", csharp, ignoreLineEndingDifferences: true); }
public void WriteCSharpCode_SkipsLinePragma_WithoutSource() { // Arrange var writer = new DesignTimeNodeWriter(); var context = TestCodeRenderingContext.CreateDesignTime(); var node = new CSharpCodeIntermediateNode(); IntermediateNodeBuilder.Create(node) .Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = "if (true) { }" }); // Act writer.WriteCSharpCode(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"if (true) { } ", csharp, ignoreLineEndingDifferences: true); }
public void WriteCSharpCode_WritesPadding_WithSource() { // Arrange var writer = new DesignTimeNodeWriter(); var context = TestCodeRenderingContext.CreateDesignTime(); var node = new CSharpCodeIntermediateNode() { Source = new SourceSpan("test.cshtml", 0, 0, 0, 17), }; IntermediateNodeBuilder.Create(node) .Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = " if (true) { }", }); // Act writer.WriteCSharpCode(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Equal( @"#line 1 ""test.cshtml"" if (true) { } #line default #line hidden ", csharp, ignoreLineEndingDifferences: true); }
public override void WriteCSharpCode(CodeRenderingContext context, CSharpCodeIntermediateNode node) { var isWhitespaceStatement = true; for (var i = 0; i < node.Children.Count; i++) { var token = node.Children[i] as IntermediateToken; if (token == null || !string.IsNullOrWhiteSpace(token.Content)) { isWhitespaceStatement = false; break; } } if (isWhitespaceStatement) { return; } for (var i = 0; i < node.Children.Count; i++) { if (node.Children[i] is IntermediateToken token && token.IsCSharp) { context.CodeWriter.Write(token.Content); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { if (documentNode.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind) { return; } var modelType = ModelDirective.GetModelType(documentNode); var visitor = new Visitor(); visitor.Visit(documentNode); var @class = visitor.Class; var viewDataType = $"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<{modelType}>"; var vddProperty = new CSharpCodeIntermediateNode(); vddProperty.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = $"public {viewDataType} ViewData => ({viewDataType})PageContext?.ViewData;", }); @class.Children.Add(vddProperty); var modelProperty = new CSharpCodeIntermediateNode(); modelProperty.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = $"public {modelType} Model => ViewData.Model;", }); @class.Children.Add(modelProperty); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); if (@namespace == null || string.IsNullOrEmpty(@namespace.Content)) { // No namespace node or it's incomplete. Skip. return; } var @class = documentNode.FindPrimaryClass(); if (@class == null || string.IsNullOrEmpty(@class.ClassName)) { // No class node or it's incomplete. Skip. return; } var generatedTypeName = $"{@namespace.Content}.{@class.ClassName}"; // The MVC attributes require a relative path to be specified so that we can make a view engine path. // We can't use a rooted path because we don't know what the project root is. // // If we can't sanitize the path, we'll just set it to null and let is blow up at runtime - we don't // want to create noise if this code has to run in some unanticipated scenario. var escapedPath = MakeVerbatimStringLiteral(ConvertToViewEnginePath(codeDocument.Source.RelativePath)); string attribute; if (documentNode.DocumentKind == MvcViewDocumentClassifierPass.MvcViewDocumentKind) { attribute = $"[assembly:{RazorViewAttribute}({escapedPath}, typeof({generatedTypeName}))]"; } else if (documentNode.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind && PageDirective.TryGetPageDirective(documentNode, out var pageDirective)) { var escapedRoutePrefix = MakeVerbatimStringLiteral(pageDirective.RouteTemplate); attribute = $"[assembly:{RazorPageAttribute}({escapedPath}, typeof({generatedTypeName}), {escapedRoutePrefix})]"; } else { return; } var index = documentNode.Children.IndexOf(@namespace); Debug.Assert(index >= 0); var pageAttribute = new CSharpCodeIntermediateNode(); pageAttribute.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = attribute, }); documentNode.Children.Insert(index, pageAttribute); }
/// <inheritdoc /> protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { if (!TryComputeNamespaceAndClass( codeDocument.Source.FilePath, codeDocument.Source.RelativePath, out var computedNamespace, out var computedClass)) { // If we can't compute a nice namespace (no relative path) then just generate something // mangled. computedNamespace = BaseNamespace; computedClass = CSharpIdentifier.GetClassNameFromPath(codeDocument.Source.FilePath) ?? "__BlazorComponent"; } if (MangleClassNames) { computedClass = "__" + computedClass; } @namespace.Content = computedNamespace; @class.BaseType = BlazorApi.BlazorComponent.FullTypeName; @class.ClassName = computedClass; @class.Modifiers.Clear(); @class.Modifiers.Add("public"); method.ReturnType = "void"; method.MethodName = BlazorApi.BlazorComponent.BuildRenderTree; method.Modifiers.Clear(); method.Modifiers.Add("protected"); method.Modifiers.Add("override"); method.Parameters.Clear(); method.Parameters.Add(new MethodParameter() { ParameterName = "builder", TypeName = BlazorApi.RenderTreeBuilder.FullTypeName, }); // We need to call the 'base' method as the first statement. var callBase = new CSharpCodeIntermediateNode(); callBase.Annotations.Add(BuildRenderTreeBaseCallAnnotation, true); callBase.Children.Add(new IntermediateToken { Kind = TokenKind.CSharp, Content = $"base.{BlazorApi.BlazorComponent.BuildRenderTree}(builder);" }); method.Children.Insert(0, callBase); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); if (@namespace == null || string.IsNullOrEmpty(@namespace.Content)) { // No namespace node or it's incomplete. Skip. return; } var @class = documentNode.FindPrimaryClass(); if (@class == null || string.IsNullOrEmpty(@class.ClassName)) { // No class node or it's incomplete. Skip. return; } var generatedTypeName = $"{@namespace.Content}.{@class.ClassName}"; var path = codeDocument.GetRelativePath(); var escapedPath = EscapeAsVerbatimLiteral(path); string attribute; if (documentNode.DocumentKind == MvcViewDocumentClassifierPass.MvcViewDocumentKind) { attribute = $"[assembly:{RazorViewAttribute}({escapedPath}, typeof({generatedTypeName}))]"; } else if (documentNode.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind && PageDirective.TryGetPageDirective(documentNode, out var pageDirective)) { var escapedRoutePrefix = EscapeAsVerbatimLiteral(pageDirective.RouteTemplate); attribute = $"[assembly:{RazorPageAttribute}({escapedPath}, typeof({generatedTypeName}), {escapedRoutePrefix})]"; } else { return; } var index = documentNode.Children.IndexOf(@namespace); Debug.Assert(index >= 0); var pageAttribute = new CSharpCodeIntermediateNode(); pageAttribute.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = attribute, }); documentNode.Children.Insert(index, pageAttribute); }
private static bool IsEmpty(CSharpCodeIntermediateNode node) { for (var i = 0; i < node.Children.Count; i++) { if (!(node.Children[i] is IntermediateToken token && string.IsNullOrWhiteSpace(token.Content))) { return(false); } } return(true); }
public override void WriteCSharpCode(CodeRenderingContext context, CSharpCodeIntermediateNode node) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (node == null) { throw new ArgumentNullException(nameof(node)); } var isWhitespaceStatement = true; for (var i = 0; i < node.Children.Count; i++) { var token = node.Children[i] as IntermediateToken; if (token == null || !string.IsNullOrWhiteSpace(token.Content)) { isWhitespaceStatement = false; break; } } if (isWhitespaceStatement) { // The runtime and design time code differ in their handling of whitespace-only // statements. At runtime we can discard them completely. At design time we need // to keep them for the editor. return; } IDisposable linePragmaScope = null; if (node.Source != null) { linePragmaScope = context.CodeWriter.BuildLinePragma(node.Source.Value); context.CodeWriter.WritePadding(0, node.Source.Value, context); } for (var i = 0; i < node.Children.Count; i++) { if (node.Children[i] is IntermediateToken token && token.IsCSharp) { _scopeStack.IncrementCurrentScopeChildCount(context); context.AddSourceMappingFor(token); context.CodeWriter.Write(token.Content); }
private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper) { var writer = new CodeWriter(); WriteClass(context, writer, tagHelper); var code = new CSharpCodeIntermediateNode(); code.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = writer.GenerateCode() }); context.Class.Children.Add(code); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); if (@namespace == null || string.IsNullOrEmpty(@namespace.Content)) { // No namespace node or it's incomplete. Skip. return; } var @class = documentNode.FindPrimaryClass(); if (@class == null || string.IsNullOrEmpty(@class.ClassName)) { // No class node or it's incomplete. Skip. return; } string generatedTypeName = $"{@namespace.Content}.{@class.ClassName}"; string templateKey = codeDocument.Source.FilePath; string escapedTemplateKey = EscapeAsVerbatimLiteral(templateKey); string attribute; if (documentNode.DocumentKind == RazorLightTemplateDocumentClassifierPass.RazorLightTemplateDocumentKind) { attribute = $"[assembly:{RazorLightTemplateAttribute}({escapedTemplateKey}, typeof({generatedTypeName}))]"; } else { return; } int index = documentNode.Children.IndexOf(@namespace); Debug.Assert(index >= 0); var pageAttribute = new CSharpCodeIntermediateNode(); pageAttribute.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = attribute, }); documentNode.Children.Insert(index, pageAttribute); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var @namespace = documentNode.FindPrimaryNamespace(); var @class = documentNode.FindPrimaryClass(); if (@namespace == null || @class == null) { return; } var directives = documentNode.FindDirectiveReferences(ComponentLayoutDirective.Directive); if (directives.Count == 0) { return; } var token = ((DirectiveIntermediateNode)directives[0].Node).Tokens.FirstOrDefault(); if (token == null) { return; } var attributeNode = new CSharpCodeIntermediateNode(); attributeNode.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = $"[{ComponentsApi.LayoutAttribute.FullTypeName}(typeof({token.Content}))]", }); // Insert the new attribute on top of the class for (var i = 0; i < @namespace.Children.Count; i++) { if (object.ReferenceEquals(@namespace.Children[i], @class)) { @namespace.Children.Insert(i, attributeNode); break; } } }
protected override void HandleMatchedContent(RazorCodeDocument codeDocument, IEnumerable <string> matchedContent) { var chosenLayoutType = matchedContent.Last(); var attributeNode = new CSharpCodeIntermediateNode(); attributeNode.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = $"[{LayoutAttributeTypeName}(typeof ({chosenLayoutType}))]" + Environment.NewLine, }); var docNode = codeDocument.GetDocumentIntermediateNode(); var namespaceNode = docNode.FindPrimaryNamespace(); var classNode = docNode.FindPrimaryClass(); var classNodeIndex = namespaceNode .Children .IndexOf(classNode); namespaceNode.Children.Insert(classNodeIndex, attributeNode); }
public void WriteCSharpCode_WhitespaceContent_DoesNothing() { // Arrange var writer = new DesignTimeNodeWriter(); var context = TestCodeRenderingContext.CreateDesignTime(); var node = new CSharpCodeIntermediateNode(); IntermediateNodeBuilder.Create(node) .Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = " \t" }); // Act writer.WriteCSharpCode(context, node); // Assert var csharp = context.CodeWriter.GenerateCode(); Assert.Empty(csharp); }
private void ConvertToBlazorPrimaryMethod(DocumentIntermediateNode documentNode) { // Replaces the default "ExecuteAsync" method with Blazor's "BuildRenderTree". // Note that DefaultDocumentWriter's VisitMethodDeclaration is hardcoded to // emit methods with no parameters, so there's no way of setting the parameters // from here. We inject the parameter later in RazorCompiler. var primaryMethod = documentNode.FindPrimaryMethod(); primaryMethod.ReturnType = "void"; primaryMethod.MethodName = BlazorComponent.BuildRenderTree; primaryMethod.Modifiers.Clear(); primaryMethod.Modifiers.Add("protected"); primaryMethod.Modifiers.Add("override"); var line = new CSharpCodeIntermediateNode(); line.Children.Add(new IntermediateToken { Kind = TokenKind.CSharp, Content = $"base.{primaryMethod.MethodName}(builder);" + Environment.NewLine }); primaryMethod.Children.Insert(0, line); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { var visitor = new Visitor(); visitor.Visit(documentNode); if (visitor.DidFindLayoutDeclaration) { visitor.MethodNode.Children.Remove(visitor.LayoutNode); var attributeNode = new CSharpCodeIntermediateNode(); attributeNode.Children.Add(new IntermediateToken() { Kind = TokenKind.CSharp, Content = $"[{LayoutAttributeTypeName}(typeof ({visitor.LayoutType}))]" + Environment.NewLine, }); var classNodeIndex = visitor .NamespaceNode .Children .IndexOf(visitor.ClassNode); visitor.NamespaceNode.Children.Insert(classNodeIndex, attributeNode); } }
protected override void OnDocumentStructureCreated(RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method); if (!TryComputeNamespaceAndClass( codeDocument.Source.FilePath, codeDocument.Source.RelativePath, out var computedNamespace, out var computedClass)) { // If we can't compute a nice namespace (no relative path) then just generate something // mangled. computedNamespace = "AspNetCore"; var checksum = Checksum.BytesToString(codeDocument.Source.GetChecksum()); computedClass = $"AspNetCore_{checksum}"; } @namespace.Content = computedNamespace; @class.ClassName = computedClass; @class.BaseType = $"global::{CodeGenerationConstants.RazorComponent.FullTypeName}"; var filePath = codeDocument.Source.RelativePath ?? codeDocument.Source.FilePath; if (string.IsNullOrEmpty(filePath)) { // It's possible for a Razor document to not have a file path. // Eg. When we try to generate code for an in memory document like default imports. var checksum = Checksum.BytesToString(codeDocument.Source.GetChecksum()); @class.ClassName = $"AspNetCore_{checksum}"; } else { @class.ClassName = CSharpIdentifier.SanitizeIdentifier(Path.GetFileNameWithoutExtension(filePath)); } @class.Modifiers.Clear(); @class.Modifiers.Add("public"); @class.Modifiers.Add("sealed"); method.MethodName = CodeGenerationConstants.RazorComponent.BuildRenderTree; method.ReturnType = "void"; method.Modifiers.Clear(); method.Modifiers.Add("public"); method.Modifiers.Add("override"); method.Parameters.Clear(); method.Parameters.Add(new MethodParameter() { TypeName = CodeGenerationConstants.RenderTreeBuilder.FullTypeName, ParameterName = CodeGenerationConstants.RazorComponent.BuildRenderTreeParameter, }); // We need to call the 'base' method as the first statement. var callBase = new CSharpCodeIntermediateNode(); callBase.Annotations.Add(BuildRenderTreeBaseCallAnnotation, true); callBase.Children.Add(new IntermediateToken { Kind = TokenKind.CSharp, Content = $"base.{CodeGenerationConstants.RazorComponent.BuildRenderTree}({CodeGenerationConstants.RazorComponent.BuildRenderTreeParameter});" }); method.Children.Insert(0, callBase); }
/// <inheritdoc /> protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { if (!TryComputeNamespaceAndClass( codeDocument.Source.FilePath, codeDocument.Source.RelativePath, out var computedNamespace, out var computedClass)) { // If we can't compute a nice namespace (no relative path) then just generate something // mangled. computedNamespace = BaseNamespace; computedClass = CSharpIdentifier.GetClassNameFromPath(codeDocument.Source.FilePath) ?? "__BlazorComponent"; } if (MangleClassNames) { computedClass = "__" + computedClass; } @namespace.Content = computedNamespace; @class.BaseType = ComponentsApi.ComponentBase.FullTypeName; @class.ClassName = computedClass; @class.Modifiers.Clear(); @class.Modifiers.Add("public"); var documentNode = codeDocument.GetDocumentIntermediateNode(); var typeParamReferences = documentNode.FindDirectiveReferences(TypeParamDirective.Directive); for (var i = 0; i < typeParamReferences.Count; i++) { var typeParamNode = (DirectiveIntermediateNode)typeParamReferences[i].Node; if (typeParamNode.HasDiagnostics) { continue; } @class.TypeParameters.Add(new TypeParameter() { ParameterName = typeParamNode.Tokens.First().Content, }); } method.ReturnType = "void"; method.MethodName = ComponentsApi.ComponentBase.BuildRenderTree; method.Modifiers.Clear(); method.Modifiers.Add("protected"); method.Modifiers.Add("override"); method.Parameters.Clear(); method.Parameters.Add(new MethodParameter() { ParameterName = "builder", TypeName = ComponentsApi.RenderTreeBuilder.FullTypeName, }); // We need to call the 'base' method as the first statement. var callBase = new CSharpCodeIntermediateNode(); callBase.Annotations.Add(BuildRenderTreeBaseCallAnnotation, true); callBase.Children.Add(new IntermediateToken { Kind = TokenKind.CSharp, Content = $"base.{ComponentsApi.ComponentBase.BuildRenderTree}(builder);" }); method.Children.Insert(0, callBase); }
public virtual void VisitCSharpCode(CSharpCodeIntermediateNode node) { VisitDefault(node); }
public override void VisitCSharpCode(CSharpCodeIntermediateNode node) { Context.NodeWriter.WriteCSharpCode(Context, node); }
internal static bool IsBuildRenderTreeBaseCall(CSharpCodeIntermediateNode node) => node.Annotations[BuildRenderTreeBaseCallAnnotation] != null;
public abstract void WriteCSharpCode(CodeRenderingContext context, CSharpCodeIntermediateNode node);