public static void Register(RazorProjectEngineBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            InjectDirective.Register(builder);
            ModelDirective.Register(builder);
            NamespaceDirective.Register(builder);
            PageDirective.Register(builder);

            FunctionsDirective.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.SetImportFeature(new MvcImportProjectFeature());
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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));
                }
            }
        }
Beispiel #4
0
 private static RazorEngine CreateEngine()
 {
     return(RazorProjectEngine.Create(b =>
     {
         PageDirective.Register(b);
     }).Engine);
 }
        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_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_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_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);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
 protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder)
 {
     PageDirective.Register(builder);
 }
Beispiel #12
0
        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);
        }
Beispiel #13
0
 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);
        }