private void CreateTypeInferenceMethod(DocumentIntermediateNode documentNode, ComponentIntermediateNode node) { var @namespace = documentNode.FindPrimaryNamespace().Content; @namespace = string.IsNullOrEmpty(@namespace) ? "__Blazor" : "__Blazor." + @namespace; @namespace += "." + documentNode.FindPrimaryClass().ClassName; var typeInferenceNode = new ComponentTypeInferenceMethodIntermediateNode() { Component = node, // Method name is generated and guaranteed not to collide, since it's unique for each // component call site. MethodName = $"Create{CSharpIdentifier.SanitizeIdentifier(node.TagName)}_{_id++}", FullTypeName = @namespace + ".TypeInference", }; node.TypeInferenceNode = typeInferenceNode; // Now we need to insert the type inference node into the tree. var namespaceNode = documentNode.Children .OfType <NamespaceDeclarationIntermediateNode>() .Where(n => n.Annotations.Contains(new KeyValuePair <object, object>(ComponentMetadata.Component.GenericTypedKey, bool.TrueString))) .FirstOrDefault(); if (namespaceNode == null) { namespaceNode = new NamespaceDeclarationIntermediateNode() { Annotations = { { ComponentMetadata.Component.GenericTypedKey, bool.TrueString }, }, Content = @namespace, }; documentNode.Children.Add(namespaceNode); } var classNode = namespaceNode.Children .OfType <ClassDeclarationIntermediateNode>() .Where(n => n.ClassName == "TypeInference") .FirstOrDefault(); if (classNode == null) { classNode = new ClassDeclarationIntermediateNode() { ClassName = "TypeInference", Modifiers = { "internal", "static", }, }; namespaceNode.Children.Add(classNode); } classNode.Children.Add(typeInferenceNode); }
public Context(NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class) { Namespace = @namespace; Class = @class; _tagHelpers = new Dictionary <TagHelperDescriptor, (string, string, string)>(); }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { using (Context.CodeWriter.BuildClassDeclaration(node.Modifiers, node.ClassName, node.BaseType, node.Interfaces)) { VisitDefault(node); } }
protected override void ExecuteCore(RazorCodeDocument codeDocument) { DocumentIntermediateNode documentNode = codeDocument.GetDocumentIntermediateNode(); NamespaceDeclarationIntermediateNode namespaceDeclaration = documentNode.Children.OfType <NamespaceDeclarationIntermediateNode>().Single(); // Get the current model type, replacing default of dynamic with IDocument string modelType = ModelDirective.GetModelType(documentNode); modelType = modelType == "dynamic" ? "IDocument" : modelType; // Set the base page type and perform default model type substitution here ClassDeclarationIntermediateNode classDeclaration = namespaceDeclaration.Children.OfType <ClassDeclarationIntermediateNode>().Single(); classDeclaration.BaseType = _baseType.Replace("<TModel>", "<" + modelType + ">"); // Add namespaces int insertIndex = namespaceDeclaration.Children.IndexOf( namespaceDeclaration.Children.OfType <UsingDirectiveIntermediateNode>().First()); foreach (string ns in _namespaces) { namespaceDeclaration.Children.Insert( insertIndex, new UsingDirectiveIntermediateNode() { Content = ns }); } codeDocument.SetDocumentIntermediateNode(documentNode); }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { _classDeclaration = node; _variableCountOffset = node.Children.Count; VisitDefault(node); }
protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method); @namespace.Content = "AspNetCore"; @class.BaseType = "global::Microsoft.AspNetCore.Mvc.RazorPages.Page"; var filePath = codeDocument.Source.RelativePath ?? codeDocument.Source.FilePath; @class.ClassName = CSharpIdentifier.GetClassNameFromPath(filePath); @class.Modifiers.Clear(); @class.Modifiers.Add("public"); method.MethodName = "ExecuteAsync"; method.Modifiers.Clear(); method.Modifiers.Add("public"); method.Modifiers.Add("async"); method.Modifiers.Add("override"); method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}"; var document = codeDocument.GetDocumentIntermediateNode(); PageDirective.TryGetPageDirective(document, out var pageDirective); EnsureValidPageDirective(codeDocument, pageDirective); AddRouteTemplateMetadataAttribute(@namespace, @class, pageDirective); }
public void Execute_HasRequiredInfo_AddsItemAndSourceChecksum() { // Arrange var engine = CreateEngine(); var pass = new MetadataAttributePass() { Engine = engine, }; var sourceDocument = TestRazorSourceDocument.Create(); var codeDocument = RazorCodeDocument.Create(sourceDocument); codeDocument.SetIdentifier("Foo/Bar"); 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", item.Identifier); Assert.Equal("test", item.Kind); Assert.Equal("Some.Namespace.Test", item.TypeName); Assert.Equal(2, @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", checksum.Identifier); }
protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method); @namespace.Content = "AspNetCore"; 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 = BytesToString(codeDocument.Source.GetChecksum()); @class.ClassName = $"AspNetCore_{checksum}"; } else { @class.ClassName = CSharpIdentifier.GetClassNameFromPath(filePath); } @class.BaseType = "global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<TModel>"; @class.Modifiers.Clear(); @class.Modifiers.Add("public"); method.MethodName = "ExecuteAsync"; method.Modifiers.Clear(); method.Modifiers.Add("public"); method.Modifiers.Add("async"); method.Modifiers.Add("override"); method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}"; }
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, }; 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 override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { var configuration = Engine.GetFeature <DefaultDocumentClassifierPassFeature>(); if (configuration != null) { for (var i = 0; i < configuration.ConfigureClass.Count; i++) { var configureClass = configuration.ConfigureClass[i]; configureClass(codeDocument, @class); } for (var i = 0; i < configuration.ConfigureNamespace.Count; i++) { var configureNamespace = configuration.ConfigureNamespace[i]; configureNamespace(codeDocument, @namespace); } for (var i = 0; i < configuration.ConfigureMethod.Count; i++) { var configureMethod = configuration.ConfigureMethod[i]; configureMethod(codeDocument, @method); } } }
public void Pass_SetsNamespaceAndClassName_ComputedFromSource_ForView() { // Arrange var document = new DocumentIntermediateNode(); var builder = IntermediateNodeBuilder.Create(document); // This will be ignored. builder.Push(new DirectiveIntermediateNode() { Directive = NamespaceDirective.Directive, Source = new SourceSpan("/Account/_ViewImports.cshtml", 0, 0, 0, 0), }); builder.Add(new DirectiveTokenIntermediateNode() { Content = "ignored" }); builder.Pop(); // This will be used. builder.Push(new DirectiveIntermediateNode() { Directive = NamespaceDirective.Directive, Source = new SourceSpan("/Account/Manage/AddUser.cshtml", 0, 0, 0, 0), }); builder.Add(new DirectiveTokenIntermediateNode() { Content = "WebApplication.Account.Manage" }); builder.Pop(); var @namespace = new NamespaceDeclarationIntermediateNode() { Content = "default" }; builder.Push(@namespace); var @class = new ClassDeclarationIntermediateNode() { ClassName = "default" }; builder.Add(@class); document.DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); var pass = new NamespaceDirective.Pass(); pass.Engine = RazorEngine.CreateEmpty(b => { }); // Act pass.Execute(codeDocument, document); // Assert Assert.Equal("WebApplication.Account.Manage", @namespace.Content); Assert.Equal("AddUser_View", @class.ClassName); }
protected virtual void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode @method) { // Intentionally empty. }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { if (Class == null) { Class = node; } base.VisitClassDeclaration(node); }
public void Execute_SuppressMetadataSourceChecksumAttributes_DoesNotGenerateSourceChecksumAttributes() { // 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 => o.SuppressMetadataSourceChecksumAttributes = true), }; 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); var child = Assert.Single(@namespace.Children); Assert.IsType <ClassDeclarationIntermediateNode>(child); }
protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { @namespace.Content = Namespace; @class.ClassName = Class; @method.MethodName = Method; }
/// <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); }
public void Execute_EscapesViewPathAndRouteWhenAddingAttributeToPage() { // Arrange var expectedAttribute = "[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@\"/test/\"\"Index.cshtml\", typeof(SomeNamespace.SomeName))]"; var irDocument = new DocumentIntermediateNode { DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind, Options = RazorCodeGenerationOptions.CreateDefault(), }; var builder = IntermediateNodeBuilder.Create(irDocument); 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 = RazorProjectEngine.Create().Engine, }; var source = TestRazorSourceDocument.Create("test", new RazorSourceDocumentProperties(filePath: null, relativePath: "test\\\"Index.cshtml")); var document = RazorCodeDocument.Create(source); // Act pass.Execute(document, irDocument); // Assert Assert.Collection(irDocument.Children, 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 override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method); if (!codeDocument.TryComputeNamespace(fallbackToRootNamespace: false, out var namespaceName)) { @namespace.Content = _useConsolidatedMvcViews ? "AspNetCoreGeneratedDocument" : "AspNetCore"; }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { using (Context.CodeWriter.BuildClassDeclaration( node.Modifiers, node.ClassName, node.BaseType, node.Interfaces, node.TypeParameters.Select(p => (p.ParameterName, p.Constraints)).ToArray())) { VisitDefault(node); } }
public void Execute_AddsRazorViewAttribute_ToViews() { // Arrange var expectedAttribute = "[assembly:global::Microsoft.AspNetCore.Mvc.Razor.Compilation.RazorViewAttribute(@\"/Views/Index.cshtml\", typeof(SomeNamespace.SomeName))]"; var irDocument = new DocumentIntermediateNode { DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind, }; var builder = IntermediateNodeBuilder.Create(irDocument); 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 document = TestRazorCodeDocument.CreateEmpty(); document.SetRelativePath("/Views/Index.cshtml"); // Act pass.Execute(document, irDocument); // Assert Assert.Collection(irDocument.Children, 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)); }
public void Pass_DoesNothing_ForUnknownDocumentKind() { // Arrange var document = new DocumentIntermediateNode(); var builder = IntermediateNodeBuilder.Create(document); builder.Push(new DirectiveIntermediateNode() { Directive = NamespaceDirective.Directive, Source = new SourceSpan(null, 0, 0, 0, 0), }); builder.Add(new DirectiveTokenIntermediateNode() { Content = "WebApplication.Account" }); builder.Pop(); var @namespace = new NamespaceDeclarationIntermediateNode() { Content = "default" }; builder.Push(@namespace); var @class = new ClassDeclarationIntermediateNode() { ClassName = "default" }; builder.Add(@class); document.DocumentKind = null; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); var pass = new NamespaceDirective.Pass(); pass.Engine = RazorEngine.CreateEmpty(b => { }); // Act pass.Execute(codeDocument, document); // Assert Assert.Equal("default", @namespace.Content); Assert.Equal("default", @class.ClassName); }
public void Pass_SetsNamespace_VerbatimFromImports() { // Arrange var document = new DocumentIntermediateNode(); var builder = IntermediateNodeBuilder.Create(document); builder.Push(new DirectiveIntermediateNode() { Directive = NamespaceDirective.Directive, Source = new SourceSpan(null, 0, 0, 0, 0), }); builder.Add(new DirectiveTokenIntermediateNode() { Content = "WebApplication.Account" }); builder.Pop(); var @namespace = new NamespaceDeclarationIntermediateNode() { Content = "default" }; builder.Push(@namespace); var @class = new ClassDeclarationIntermediateNode() { ClassName = "default" }; builder.Add(@class); document.DocumentKind = RazorPageDocumentClassifierPass.RazorPageDocumentKind; var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("ignored", "/Account/Manage/AddUser.cshtml")); var pass = new NamespaceDirective.Pass(); pass.Engine = Mock.Of <RazorEngine>(); // Act pass.Execute(codeDocument, document); // Assert Assert.Equal("WebApplication.Account", @namespace.Content); Assert.Equal("default", @class.ClassName); }
public void Execute_NoOps_ForDesignTime() { // Arrange var irDocument = new DocumentIntermediateNode { DocumentKind = MvcViewDocumentClassifierPass.MvcViewDocumentKind, Options = RazorCodeGenerationOptions.CreateDesignTimeDefault(), }; var builder = IntermediateNodeBuilder.Create(irDocument); 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 = RazorProjectEngine.Create().Engine, }; 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(@namespace, node)); }
public void Execute_NoIdentifier_Noops() { // Arrange var engine = CreateEngine(); var pass = new MetadataAttributePass() { Engine = engine, }; var sourceDocument = TestRazorSourceDocument.Create("", new RazorSourceDocumentProperties(null, null)); var codeDocument = RazorCodeDocument.Create(sourceDocument); 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 SingleChild <NamespaceDeclarationIntermediateNode>(irDocument); }
private void Rewrite(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { // Rewrite the document from a flat structure to use a sensible default structure, // a namespace and class declaration with a single 'razor' method. var children = new List <IntermediateNode>(documentNode.Children); documentNode.Children.Clear(); var @namespace = new NamespaceDeclarationIntermediateNode(); @namespace.Annotations[CommonAnnotations.PrimaryNamespace] = CommonAnnotations.PrimaryNamespace; var @class = new ClassDeclarationIntermediateNode(); @class.Annotations[CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass; var method = new MethodDeclarationIntermediateNode(); method.Annotations[CommonAnnotations.PrimaryMethod] = CommonAnnotations.PrimaryMethod; var documentBuilder = IntermediateNodeBuilder.Create(documentNode); var namespaceBuilder = IntermediateNodeBuilder.Create(documentBuilder.Current); namespaceBuilder.Push(@namespace); var classBuilder = IntermediateNodeBuilder.Create(namespaceBuilder.Current); classBuilder.Push(@class); var methodBuilder = IntermediateNodeBuilder.Create(classBuilder.Current); methodBuilder.Push(method); var visitor = new Visitor(documentBuilder, namespaceBuilder, classBuilder, methodBuilder); for (var i = 0; i < children.Count; i++) { visitor.Visit(children[i]); } // Note that this is called at the *end* of rewriting so that user code can see the tree // and look at its content to make a decision. OnDocumentStructureCreated(codeDocument, @namespace, @class, method); }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { var entries = new List <string>() { string.Join(" ", node.Modifiers), node.ClassName, node.BaseType, string.Join(", ", node.Interfaces ?? Array.Empty <string>()) }; // Avoid adding the type parameters to the baseline if they aren't present. if (node.TypeParameters != null && node.TypeParameters.Count > 0) { entries.Add(string.Join(", ", node.TypeParameters.Select(p => p.ParameterName))); } WriteContentNode(node, entries.ToArray()); }
public void FindPrimaryClass_FindsClassWithAnnotation() { // Arrange var document = new DocumentIntermediateNode(); var @class = new ClassDeclarationIntermediateNode(); @class.Annotations[CommonAnnotations.PrimaryClass] = CommonAnnotations.PrimaryClass; var builder = IntermediateNodeBuilder.Create(document); builder.Add(@class); // Act var result = document.FindPrimaryClass(); // Assert Assert.Same(@class, result); }
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node) { node.Children.Insert(0, new CSharpCodeIntermediateNode() { Children = { new IntermediateToken() { Kind = TokenKind.CSharp, Content = "#pragma warning disable 0414", } } }); node.Children.Insert(1, new CSharpCodeIntermediateNode() { Children = { new IntermediateToken() { Kind = TokenKind.CSharp, Content = $"private static {typeof(object).FullName} {DesignTimeVariable} = null;", } } }); node.Children.Insert(2, new CSharpCodeIntermediateNode() { Children = { new IntermediateToken() { Kind = TokenKind.CSharp, Content = "#pragma warning restore 0414", } } }); _directiveNode = new DesignTimeDirectiveIntermediateNode(); VisitDefault(node); node.Children.Insert(0, _directiveNode); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { ClassDeclarationIntermediateNode primaryClass = documentNode.FindPrimaryClass(); if (primaryClass == null) { return; } string fullClassName = null; foreach (IntermediateNodeReference directiveReference in documentNode.FindDirectiveReferences(InheritsDirective.Directive)) { DirectiveTokenIntermediateNode intermediateNode = ((DirectiveIntermediateNode)directiveReference.Node).Tokens .FirstOrDefault <DirectiveTokenIntermediateNode>(); if (intermediateNode != null) { fullClassName = intermediateNode.Content; break; } } if (fullClassName == null) { return; } if (PartialClassMode) { var info = new TypeReferenceInfo(fullClassName); var pns = documentNode.FindPrimaryNamespace().Content = info.Namespace; primaryClass.BaseType = null; primaryClass.Modifiers.Add("partial"); primaryClass.ClassName = info.Name; } else { primaryClass.BaseType = fullClassName; } }
protected override void OnDocumentStructureCreated( RazorCodeDocument codeDocument, NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, MethodDeclarationIntermediateNode method) { var documentNode = codeDocument.GetDocumentIntermediateNode(); foreach (var @using in @namespace.Children.OfType <UsingDirectiveIntermediateNode>()) { documentNode.Children.Add(@using); } foreach (var child in method.Children) { documentNode.Children.Add(child); } documentNode.Children.Remove(@namespace); return; }