public static bool TryGetPageDirective(ILogger logger, RazorProjectItem projectItem, out string template) { if (projectItem == null) { throw new ArgumentNullException(nameof(projectItem)); } var codeDocument = PageDirectiveEngine.Process(projectItem); var documentIRNode = codeDocument.GetDocumentIntermediateNode(); if (PageDirective.TryGetPageDirective(documentIRNode, out var pageDirective)) { if (pageDirective.DirectiveNode is MalformedDirectiveIntermediateNode malformedNode) { logger.MalformedPageDirective(projectItem.FilePath, malformedNode.Diagnostics); } template = pageDirective.RouteTemplate; return(true); } template = null; return(false); }
private RazorEngine GetRazorEngine() { var razorEngine = RazorEngine.Create(builder => { InjectDirective.Register(builder); ModelDirective.Register(builder); NamespaceDirective.Register(builder); PageDirective.Register(builder); FunctionsDirective.Register(builder); InheritsDirective.Register(builder); SectionDirective.Register(builder); ////builder.AddTargetExtension(new TemplateTargetExtension() ////{ //// TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult", ////}); ////builder.Features.Add(new SuppressChecksumOptionsFeature()); builder.Features.Add(new ModelExpressionPass()); builder.Features.Add(new PagesPropertyInjectionPass()); builder.Features.Add(new ViewComponentTagHelperPass()); builder.Features.Add(new RazorPageDocumentClassifierPass()); builder.Features.Add(new MvcViewDocumentClassifierPass2(RuntimeTemplatesNamespace, BaseViewName)); builder.Features.Add(new AssemblyAttributeInjectionPass2()); if (!builder.DesignTime) { //builder.Features.Add(new InstrumentationPass()); } }); return(razorEngine); }
static bool TryGetPageDirective( ILogger logger, RazorSourceDocument sourceDocument, out string template) { var codeDocument = RazorCodeDocument.Create(sourceDocument); PageDirectiveEngine.Process(codeDocument); var documentIRNode = codeDocument.GetDocumentIntermediateNode(); if (PageDirective.TryGetPageDirective(documentIRNode, out var pageDirective)) { if (pageDirective.DirectiveNode is MalformedDirectiveIntermediateNode malformedNode) { logger.MalformedPageDirective(sourceDocument.FilePath, malformedNode.Diagnostics); } template = pageDirective.RouteTemplate; return(true); } template = null; return(false); }
public void Execute_NoOpsForBlazorComponents() { // Arrange var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.razor"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("Hello world", properties)); codeDocument.SetFileKind(FileKinds.Component); var engine = CreateProjectEngine(b => { PageDirective.Register(b); }).Engine; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new CreateNewOnMetadataUpdateAttributePass { Engine = engine }; var documentClassifier = new DefaultDocumentClassifierPass { Engine = engine }; // Act documentClassifier.Execute(codeDocument, irDocument); pass.Execute(codeDocument, irDocument); var visitor = new Visitor(); visitor.Visit(irDocument); // Assert Assert.Empty(visitor.ExtensionNodes); }
public static bool TryGetPageDirective(DocumentIntermediateNode documentNode, out PageDirective pageDirective) { var visitor = new Visitor(); for (var i = 0; i < documentNode.Children.Count; i++) { visitor.Visit(documentNode.Children[i]); } if (visitor.DirectiveTokens == null) { pageDirective = null; return(false); } var tokens = visitor.DirectiveTokens.ToList(); string routeTemplate = null; if (tokens.Count > 0) { routeTemplate = TrimQuotes(tokens[0].Content); } pageDirective = new PageDirective(routeTemplate, visitor.DirectiveNode); return(true); }
private void EnsureValidPageDirective(RazorCodeDocument codeDocument, PageDirective pageDirective) { Debug.Assert(pageDirective != null); if (pageDirective.DirectiveNode.IsImported()) { pageDirective.DirectiveNode.Diagnostics.Add( RazorExtensionsDiagnosticFactory.CreatePageDirective_CannotBeImported(pageDirective.DirectiveNode.Source.Value)); } else { // The document contains a page directive and it is not imported. // We now want to make sure this page directive exists at the top of the file. // We are going to do that by re-parsing the document until the very first line that is not Razor comment // or whitespace. We then make sure the page directive still exists in the re-parsed IR tree. var leadingDirectiveCodeDocument = RazorCodeDocument.Create(codeDocument.Source); LeadingDirectiveParsingEngine.Engine.Process(leadingDirectiveCodeDocument); var leadingDirectiveDocumentNode = leadingDirectiveCodeDocument.GetDocumentIntermediateNode(); if (!PageDirective.TryGetPageDirective(leadingDirectiveDocumentNode, out var _)) { // The page directive is not the leading directive. Add an error. pageDirective.DirectiveNode.Diagnostics.Add( RazorExtensionsDiagnosticFactory.CreatePageDirective_MustExistAtTheTopOfFile(pageDirective.DirectiveNode.Source.Value)); } } }
private RazorEngine CreateRuntimeEngine() { return(CreateProjectEngine(b => { PageDirective.Register(b); }).Engine); }
private RazorEngine CreateEngine() { return(RazorProjectEngine.Create(b => { PageDirective.Register(b); }).Engine); }
public void AtDirective_PageDirectiveChildren() { string[] tests = new string[] { "@page { @top-left-corner { foo } }", "@page { @top-left { foo } }", "@page { @top-center { foo } }", "@page { @top-right { foo } }", "@page { @top-right-corner { foo } }", "@page { @bottom-left-corner { foo } }", "@page { @bottom-left { foo } }", "@page { @bottom-center { foo } }", "@page { @bottom-right { foo } }", "@page { @bottom-right-corner { foo } }", "@page { @left-top { foo } }", "@page { @left-middle { foo } }", "@page { @left-bottom { foo } }", "@page { @right-top { foo } }", "@page { @right-middle { foo } }", "@page { @right-bottom { foo } }", "@page { @RIGHT-bottom { foo } }", }; MarginDirectiveType[] types = new MarginDirectiveType[] { MarginDirectiveType.TopLeftCorner, MarginDirectiveType.TopLeft, MarginDirectiveType.TopCenter, MarginDirectiveType.TopRight, MarginDirectiveType.TopRightCorner, MarginDirectiveType.BottomLeftCorner, MarginDirectiveType.BottomLeft, MarginDirectiveType.BottomCenter, MarginDirectiveType.BottomRight, MarginDirectiveType.BottomRightCorner, MarginDirectiveType.LeftTop, MarginDirectiveType.LeftMiddle, MarginDirectiveType.LeftBottom, MarginDirectiveType.RightTop, MarginDirectiveType.RightMiddle, MarginDirectiveType.RightBottom, MarginDirectiveType.Unknown, }; for (int i = 0; i < tests.Length; i++) { PageDirective s = new PageDirective(); ITextProvider tp = new StringTextProvider(tests[i]); Assert.IsTrue(s.Parse(new ItemFactory(tp, null), tp, Helpers.MakeTokenStream(tp))); Assert.AreEqual(1, s.PageDirectiveBlock.Margins.Count); Assert.AreEqual(types[i], s.PageDirectiveBlock.Margins[0].DirectiveType); } }
private static RazorCodeDocument CreateCodeDocument(string text) { var projectItem = new TestRazorProjectItem("c:/Test.razor", "c:/Test.razor", "Test.razor") { Content = text }; var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty, (builder) => { PageDirective.Register(builder); }); var codeDocument = projectEngine.Process(projectItem); codeDocument.SetFileKind(FileKinds.Component); return(codeDocument); }
public void TryGetPageDirective_ParsesRouteTemplate() { // Arrange var content = "@page \"some-route-template\""; var sourceDocument = RazorSourceDocument.Create(content, "file"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var engine = CreateEngine(); var irDocument = CreateIRDocument(engine, codeDocument); // Act var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); // Assert Assert.True(result); Assert.Equal("some-route-template", pageDirective.RouteTemplate); }
public void TryGetPageDirective_ReturnsFalse_IfPageDoesNotHaveDirective() { // Arrange var content = "Hello world"; var sourceDocument = RazorSourceDocument.Create(content, "file"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var engine = CreateEngine(); var irDocument = CreateIRDocument(engine, codeDocument); // Act var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); // Assert Assert.False(result); Assert.Null(pageDirective); }
public void TryGetPageDirective_ReturnsTrue_IfContentHasDirective() { // Arrange var content = "@page"; var sourceDocument = RazorSourceDocument.Create(content, "file"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var engine = CreateEngine(); var irDocument = CreateIRDocument(engine, codeDocument); // Act var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); // Assert Assert.True(result); Assert.Null(pageDirective.RouteTemplate); }
public void TryGetPageDirective_ReturnsTrue_IfPageIsImported() { // Arrange var content = "Hello world"; var sourceDocument = RazorSourceDocument.Create(content, "file"); var importDocument = RazorSourceDocument.Create("@page", "imports.cshtml"); var codeDocument = RazorCodeDocument.Create(sourceDocument, new[] { importDocument }); var engine = CreateEngine(); var irDocument = CreateIRDocument(engine, codeDocument); // Act var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); // Assert Assert.True(result); Assert.Null(pageDirective.RouteTemplate); }
public void TryGetPageDirective_ReturnsTrue_IfPageIsMalformed() { // Arrange var content = "@page \"some-route-template\" Invalid"; var sourceDocument = RazorSourceDocument.Create(content, "file"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var engine = CreateEngine(); var irDocument = CreateIRDocument(engine, codeDocument); // Act var result = PageDirective.TryGetPageDirective(irDocument, out var pageDirective); // Assert Assert.True(result); Assert.Equal("some-route-template", pageDirective.RouteTemplate); Assert.NotNull(pageDirective.DirectiveNode); }
public async Task Handle_AddOneUsingToPageDirective() { // Arrange var documentPath = "c:/Test.cshtml"; var documentUri = new Uri(documentPath); var contents = $"@page{Environment.NewLine}@model IndexModel"; var projectItem = new TestRazorProjectItem("c:/Test.cshtml", "c:/Test.cshtml", "Test.cshtml") { Content = contents }; var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, TestRazorProjectFileSystem.Empty, (builder) => { PageDirective.Register(builder); ModelDirective.Register(builder); }); var codeDocument = projectEngine.Process(projectItem); codeDocument.SetFileKind(FileKinds.Legacy); var resolver = new AddUsingsCodeActionResolver(LegacyDispatcher, CreateDocumentResolver(documentPath, codeDocument)); var actionParams = new AddUsingsCodeActionParams { Uri = documentUri, Namespace = "System" }; var data = JObject.FromObject(actionParams); // Act var workspaceEdit = await resolver.ResolveAsync(data, default); // Assert Assert.NotNull(workspaceEdit); Assert.NotNull(workspaceEdit.DocumentChanges); Assert.Single(workspaceEdit.DocumentChanges); var documentChanges = workspaceEdit.DocumentChanges.ToArray(); var addUsingsChange = documentChanges[0]; Assert.True(addUsingsChange.IsTextDocumentEdit); var firstEdit = Assert.Single(addUsingsChange.TextDocumentEdit.Edits); Assert.Equal(1, firstEdit.Range.Start.Line); Assert.Equal($"@using System{Environment.NewLine}", firstEdit.NewText); }
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; 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.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_AddsAttributes() { // Arrange var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.cshtml"); var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("Hello world", properties)); var engine = CreateProjectEngine(b => { PageDirective.Register(b); }).Engine;; var irDocument = CreateIRDocument(engine, codeDocument); var pass = new CreateNewOnMetadataUpdateAttributePass { Engine = engine }; var documentClassifier = new MvcViewDocumentClassifierPass { Engine = engine }; // Act documentClassifier.Execute(codeDocument, irDocument); pass.Execute(codeDocument, irDocument); var visitor = new Visitor(); visitor.Visit(irDocument); // Assert Assert.Collection( visitor.ExtensionNodes, node => { var attributeNode = Assert.IsType <RazorCompiledItemMetadataAttributeIntermediateNode>(node); Assert.Equal("Identifier", attributeNode.Key); Assert.Equal("/Test.cshtml", attributeNode.Value); }, node => { Assert.IsType <CreateNewOnMetadataUpdateAttributePass.CreateNewOnMetadataUpdateAttributeIntermediateNode>(node); }); }
public static void Register(RazorProjectEngineBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } InjectDirective.Register(builder); ModelDirective.Register(builder); PageDirective.Register(builder); SectionDirective.Register(builder); builder.Features.Add(new DefaultTagHelperDescriptorProvider()); builder.Features.Add(new ViewComponentTagHelperDescriptorProvider()); builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension() { TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult", }); builder.Features.Add(new ModelExpressionPass()); builder.Features.Add(new PagesPropertyInjectionPass()); builder.Features.Add(new ViewComponentTagHelperPass()); builder.Features.Add(new RazorPageDocumentClassifierPass(builder.Configuration.UseConsolidatedMvcViews)); builder.Features.Add(new MvcViewDocumentClassifierPass(builder.Configuration.UseConsolidatedMvcViews)); builder.Features.Add(new MvcImportProjectFeature()); // The default C# language version for what this Razor configuration supports. builder.SetCSharpLanguageVersion(LanguageVersion.CSharp8); if (builder.Configuration.LanguageVersion.CompareTo(RazorLanguageVersion.Version_6_0) >= 0) { builder.Features.Add(new CreateNewOnMetadataUpdateAttributePass()); } }
public static void Register(RazorProjectEngineBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } FunctionsDirective.Register(builder); InjectDirective.Register(builder); ModelDirective.Register(builder); NamespaceDirective.Register(builder); PageDirective.Register(builder); InheritsDirective.Register(builder); SectionDirective.Register(builder); builder.Features.Add(new DefaultTagHelperDescriptorProvider()); builder.Features.Add(new ViewComponentTagHelperDescriptorProvider()); builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension()); builder.AddTargetExtension(new TemplateTargetExtension() { TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult", }); builder.Features.Add(new ModelExpressionPass()); builder.Features.Add(new PagesPropertyInjectionPass()); builder.Features.Add(new ViewComponentTagHelperPass()); builder.Features.Add(new RazorPageDocumentClassifierPass()); builder.Features.Add(new MvcViewDocumentClassifierPass()); builder.Features.Add(new AssemblyAttributeInjectionPass()); builder.Features.Add(new InstrumentationPass()); builder.Features.Add(new MvcImportProjectFeature()); // The default C# language version for what this Razor configuration supports. builder.SetCSharpLanguageVersion(LanguageVersion.CSharp7_3); }
protected void ParsePageDirective(Group attrname, Group attrval) { PageDirective pd = new PageDirective(); string name; string value; for (int i = 1; i < attrname.Captures.Count; i++) { name = attrname.Captures[i].Value; value = attrval.Captures[i].Value; switch (name.ToLower()) { case "language": switch (value) { case CSHARP: _doc.Language = LanguageEnum.CSharp; break; case VB: _doc.Language = LanguageEnum.VB; break; } break; case "inherits": _doc.Inherits = value; break; case "masterpagefile": _doc.HasMaster = true; pd.MasterPageFile = value; break; } } _doc.Directives.Add(pd); }
public void PageDirective_ParseTest() { string text = "@page { }"; ITextProvider tp = new StringTextProvider(text); TokenStream ts = Helpers.MakeTokenStream(tp); PageDirective pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); text = "@page:left { }"; tp = new StringTextProvider(text); ts = Helpers.MakeTokenStream(tp); pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); Assert.IsTrue(tp.CompareTo(pd.Keyword.Start, "page", ignoreCase: false)); Assert.AreEqual("left", tp.GetText(pd.PseudoPage.Start, pd.PseudoPage.Length)); Assert.IsNotNull(pd.Block.OpenCurlyBrace); Assert.IsNotNull(pd.Block.CloseCurlyBrace); text = "@page :right{ }"; tp = new StringTextProvider(text); ts = Helpers.MakeTokenStream(tp); pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); Assert.IsTrue(tp.CompareTo(pd.Keyword.Start, "page", ignoreCase: false)); Assert.AreEqual("right", tp.GetText(pd.PseudoPage.Start, pd.PseudoPage.Length)); Assert.IsNotNull(pd.Block.OpenCurlyBrace); Assert.IsNotNull(pd.Block.CloseCurlyBrace); text = "@page foo:first{ }"; tp = new StringTextProvider(text); ts = Helpers.MakeTokenStream(tp); pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); Assert.IsTrue(tp.CompareTo(pd.Keyword.Start, "page", ignoreCase: false)); Assert.IsTrue(tp.CompareTo(pd.Identifier.Start, "foo", ignoreCase: false)); Assert.AreEqual("first", tp.GetText(pd.PseudoPage.Start, pd.PseudoPage.Length)); Assert.IsNotNull(pd.Block.OpenCurlyBrace); Assert.IsNotNull(pd.Block.CloseCurlyBrace); text = "@page :foo{ @top-left { } }"; tp = new StringTextProvider(text); ts = Helpers.MakeTokenStream(tp); pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); Assert.AreEqual(1, pd.PageDirectiveBlock.Margins.Count); Assert.AreEqual(MarginDirectiveType.TopLeft, pd.PageDirectiveBlock.Margins[0].DirectiveType); Assert.IsTrue(tp.CompareTo(pd.PageDirectiveBlock.Margins[0].Keyword.Start, "top-left", ignoreCase: false)); text = "@page"; tp = new StringTextProvider(text); ts = Helpers.MakeTokenStream(tp); pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); Assert.IsNull(pd.Block); text = "@page :right{ @top-left { }"; tp = new StringTextProvider(text); ts = Helpers.MakeTokenStream(tp); pd = new PageDirective(); Assert.IsTrue(pd.Parse(new ItemFactory(tp, null), tp, ts)); Assert.AreEqual(1, pd.PageDirectiveBlock.Margins.Count); Assert.IsTrue(tp.CompareTo(pd.PageDirectiveBlock.Margins[0].Keyword.Start, "top-left", ignoreCase: false)); Assert.IsNotNull(pd.PageDirectiveBlock.Margins[0].RuleBlock.OpenCurlyBrace); Assert.IsNotNull(pd.PageDirectiveBlock.Margins[0].RuleBlock.CloseCurlyBrace); Assert.IsNotNull(pd.Block.OpenCurlyBrace); Assert.IsNull(pd.Block.CloseCurlyBrace); }
public void Generate(AspxDocument doc, string outfile) { using (StreamWriter sw = new StreamWriter(outfile, false, new UTF8Encoding(true))) { if (!string.IsNullOrEmpty(doc.Inherits)) { //sw.WriteLine(string.Format("@inherits {0}", doc.Inherits)); } foreach (Directive directive in doc.Directives) { PageDirective pageDirective = directive as PageDirective; if (pageDirective != null) { if (!string.IsNullOrEmpty(pageDirective.MasterPageFile)) { sw.WriteLine(string.Format("@{{\r\n\tLayout = \"{0}\";\r\n}}", pageDirective.MasterPageFile.Replace(".Master", ".cshtml"))); } } ImportDirective importDirective = directive as ImportDirective; if (importDirective != null) { sw.WriteLine(string.Format("@using {0}", importDirective.Namespace)); } } bool afterCodeBlock = false; foreach (Block block in doc.Blocks) { HtmlBlock htmlBlock = block as HtmlBlock; if (htmlBlock != null) { string contents = doc.Contents.Substring(block.Index, block.Length); Regex regex = new Regex("^\\s*<"); //Check if started with < if (!afterCodeBlock || regex.IsMatch(contents)) { sw.Write(contents); //Write the contents directlhy } else { //Wrap it inside <text>...</text> sw.Write("<text>"); sw.Write(contents); sw.Write("</text>"); } } afterCodeBlock = false; CodeBlock codeBlock = block as CodeBlock; if (codeBlock != null) { if (codeBlock.IsFirst) { sw.WriteLine(" @{"); } sw.WriteLine("\r\n" + doc.Contents.Substring(block.Index + 2, block.Length - 4)); if (codeBlock.IsLast) { sw.WriteLine("}"); } afterCodeBlock = true; } ExpressionBlock expressionBlock = block as ExpressionBlock; if (expressionBlock != null) { sw.Write(string.Format("@{0} ", doc.Contents.Substring(block.Index + 3, block.Length - 5).Trim())); } CommentBlock commentBlock = block as CommentBlock; if (commentBlock != null) { sw.Write(string.Format("@*{0}*@", doc.Contents.Substring(block.Index + 3, block.Length - 6))); } ContentPlaceHolderBlock cphBlock = block as ContentPlaceHolderBlock; if (cphBlock != null) { if ("MainContent".Equals(cphBlock.ID)) { sw.WriteLine("\r\n\t@RenderBody()"); } } } } }
private static void AddRouteTemplateMetadataAttribute(NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, PageDirective pageDirective) { if (string.IsNullOrEmpty(pageDirective.RouteTemplate)) { return; } var classIndex = @namespace.Children.IndexOf(@class); if (classIndex == -1) { return; } var metadataAttributeNode = new RazorCompiledItemMetadataAttributeIntermediateNode { Key = RouteTemplateKey, Value = pageDirective.RouteTemplate, }; // Metadata attributes need to be inserted right before the class declaration. @namespace.Children.Insert(classIndex, metadataAttributeNode); }
protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder) { PageDirective.Register(builder); }
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { return(PageDirective.TryGetPageDirective(documentNode, out var pageDirective)); }
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode) { if (documentNode.Options.DesignTime) { return; } 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); }