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 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));
            }
        }
    }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
    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);
    }
Ejemplo n.º 5
0
    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);
    }
Ejemplo n.º 6
0
    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);
    }
Ejemplo n.º 7
0
    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);
    }
Ejemplo n.º 8
0
    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);
    }
    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);
    }
Ejemplo n.º 10
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);
    }