protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
        {
            var @class = documentNode.FindPrimaryClass();

            if (@class == null)
            {
                return;
            }

            var directiveNodes = new List <IntermediateNodeReference>();

            directiveNodes.AddRange(documentNode.FindDirectiveReferences(FunctionsDirective.Directive));

            if (FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                directiveNodes.AddRange(documentNode.FindDirectiveReferences(ComponentCodeDirective.Directive));
            }

            // Now we have all the directive nodes, we want to add them to the end of the class node in document order.
            var orderedDirectives = directiveNodes.OrderBy(n => n.Node.Source?.AbsoluteIndex);

            foreach (var directiveReference in orderedDirectives)
            {
                var node = directiveReference.Node;
                for (var i = 0; i < node.Children.Count; i++)
                {
                    @class.Children.Add(node.Children[i]);
                }

                // We don't want to keep the original directive node around anymore.
                // Otherwise this can cause unintended side effects in the subsequent passes.
                directiveReference.Remove();
            }
        }
示例#2
0
        protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
        {
            if (FileKinds.IsComponent(codeDocument.GetFileKind()))
            {
                // Hot reload does not apply to components.
                return;
            }

            var @namespace = documentNode.FindPrimaryNamespace();
            var @class     = documentNode.FindPrimaryClass();

            var classIndex = @namespace.Children.IndexOf(@class);

            if (classIndex == -1)
            {
                return;
            }

            var identifierFeature = Engine.Features.OfType <IMetadataIdentifierFeature>().First();
            var identifier        = identifierFeature.GetIdentifier(codeDocument, codeDocument.Source);

            var metadataAttributeNode = new CreateNewOnMetadataUpdateAttributeIntermediateNode();

            // Metadata attributes need to be inserted right before the class declaration.
            @namespace.Children.Insert(classIndex, metadataAttributeNode);

            // [global:Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("Identifier", "/Views/Home/Index.cshtml")]
            @namespace.Children.Insert(classIndex, new RazorCompiledItemMetadataAttributeIntermediateNode
            {
                Key   = "Identifier",
                Value = identifier,
            });
        }
    public RazorSyntaxTree Execute(RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree)
    {
        if (FileKinds.IsComponent(codeDocument.GetFileKind()))
        {
            // Nothing to do here.
            return(syntaxTree);
        }

        var sectionVerifier = new NestedSectionVerifier(syntaxTree);

        return(sectionVerifier.Verify());
    }
        private static DocumentResolver CreateDocumentResolver(string documentPath, RazorCodeDocument codeDocument)
        {
            var sourceTextChars = new char[codeDocument.Source.Length];

            codeDocument.Source.CopyTo(0, sourceTextChars, 0, codeDocument.Source.Length);
            var sourceText       = SourceText.From(new string(sourceTextChars));
            var documentSnapshot = Mock.Of <DocumentSnapshot>(document =>
                                                              document.GetGeneratedOutputAsync() == Task.FromResult(codeDocument) &&
                                                              document.FileKind == codeDocument.GetFileKind() &&
                                                              document.GetTextAsync() == Task.FromResult(sourceText), MockBehavior.Strict);
            var documentResolver = new Mock <DocumentResolver>(MockBehavior.Strict);

            documentResolver.Setup(resolver => resolver.TryResolveDocument(documentPath, out documentSnapshot))
            .Returns(true);
            return(documentResolver.Object);
        }
示例#5
0
    protected override void ExecuteCore(RazorCodeDocument codeDocument)
    {
        var syntaxTree = codeDocument.GetSyntaxTree();

        ThrowForMissingDocumentDependency(syntaxTree);

        var descriptors = codeDocument.GetTagHelpers();

        if (descriptors == null)
        {
            var feature = Engine.GetFeature <ITagHelperFeature>();
            if (feature == null)
            {
                // No feature, nothing to do.
                return;
            }

            descriptors = feature.GetDescriptors();
        }

        var parserOptions = codeDocument.GetParserOptions();

        // We need to find directives in all of the *imports* as well as in the main razor file
        //
        // The imports come logically before the main razor file and are in the order they
        // should be processed.
        DirectiveVisitor visitor;

        if (FileKinds.IsComponent(codeDocument.GetFileKind()) &&
            (parserOptions == null || parserOptions.FeatureFlags.AllowComponentFileKind))
        {
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var currentNamespace);
            visitor = new ComponentDirectiveVisitor(codeDocument.Source.FilePath, descriptors, currentNamespace);
        }
        else
        {
            visitor = new TagHelperDirectiveVisitor(descriptors);
        }
        var imports = codeDocument.GetImportSyntaxTrees();

        if (imports != null)
        {
            for (var i = 0; i < imports.Count; i++)
            {
                var import = imports[i];
                visitor.Visit(import);
            }
        }

        visitor.Visit(syntaxTree);

        // This will always be null for a component document.
        var tagHelperPrefix = visitor.TagHelperPrefix;

        descriptors = visitor.Matches.ToArray();

        var context = TagHelperDocumentContext.Create(tagHelperPrefix, descriptors);

        codeDocument.SetTagHelperContext(context);

        if (descriptors.Count == 0)
        {
            // No descriptors, no-op.
            return;
        }

        var rewrittenSyntaxTree = TagHelperParseTreeRewriter.Rewrite(syntaxTree, tagHelperPrefix, descriptors);

        codeDocument.SetSyntaxTree(rewrittenSyntaxTree);
    }
        /// <inheritdoc />
        protected override void OnDocumentStructureCreated(
            RazorCodeDocument codeDocument,
            NamespaceDeclarationIntermediateNode @namespace,
            ClassDeclarationIntermediateNode @class,
            MethodDeclarationIntermediateNode method)
        {
            if (!codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var computedNamespace) ||
                !TryComputeClassName(codeDocument, out var computedClass))
            {
                // If we can't compute a nice namespace (no relative path) then just generate something
                // mangled.
                computedNamespace = FallbackRootNamespace;
                var checksum = Checksum.BytesToString(codeDocument.Source.GetChecksum());
                computedClass = $"AspNetCore_{checksum}";
            }

            var documentNode = codeDocument.GetDocumentIntermediateNode();

            if (char.IsLower(computedClass, 0))
            {
                // We don't allow component names to start with a lowercase character.
                documentNode.Diagnostics.Add(
                    ComponentDiagnosticFactory.Create_ComponentNamesCannotStartWithLowerCase(computedClass, documentNode.Source));
            }

            if (MangleClassNames)
            {
                computedClass = ComponentMetadata.MangleClassName(computedClass);
            }

            @namespace.Content = computedNamespace;
            @class.ClassName   = computedClass;
            @class.Modifiers.Clear();
            @class.Modifiers.Add("public");
            @class.Modifiers.Add("partial");

            if (FileKinds.IsComponentImport(codeDocument.GetFileKind()))
            {
                // We don't want component imports to be considered as real component.
                // But we still want to generate code for it so we can get diagnostics.
                @class.BaseType = typeof(object).FullName;

                method.ReturnType = "void";
                method.MethodName = "Execute";
                method.Modifiers.Clear();
                method.Modifiers.Add("protected");

                method.Parameters.Clear();
            }
            else
            {
                @class.BaseType = ComponentsApi.ComponentBase.FullTypeName;

                var typeParamReferences = documentNode.FindDirectiveReferences(ComponentTypeParamDirective.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,
                        Constraints   = typeParamNode.Tokens.Skip(1).FirstOrDefault()?.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 = ComponentsApi.RenderTreeBuilder.BuilderParameter,
                    TypeName      = ComponentsApi.RenderTreeBuilder.FullTypeName,
                });
            }
        }
 protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
 {
     return(FileKinds.IsComponent(codeDocument.GetFileKind()));
 }
        private (RazorLanguageKind, TextEdit[]) GetFormattedEdits(RazorCodeDocument codeDocument, string expected, int positionBeforeTriggerChar)
        {
            var mappingService = new DefaultRazorDocumentMappingService();
            var languageKind   = mappingService.GetLanguageKind(codeDocument, positionBeforeTriggerChar);

            var expectedText = SourceText.From(expected);

            var(expectedCodeDocument, _) = CreateCodeDocumentAndSnapshot(expectedText, codeDocument.Source.FilePath, fileKind: codeDocument.GetFileKind());

            var edits = Array.Empty <TextEdit>();

            if (languageKind == RazorLanguageKind.CSharp)
            {
                var beforeCSharpText = SourceText.From(codeDocument.GetCSharpDocument().GeneratedCode);
                var afterCSharpText  = SourceText.From(expectedCodeDocument.GetCSharpDocument().GeneratedCode);
                edits = SourceTextDiffer.GetMinimalTextChanges(beforeCSharpText, afterCSharpText, lineDiffOnly: false).Select(c => c.AsTextEdit(beforeCSharpText)).ToArray();
            }
            else if (languageKind == RazorLanguageKind.Html)
            {
                var beforeHtmlText = SourceText.From(codeDocument.GetHtmlDocument().GeneratedHtml);
                var afterHtmlText  = SourceText.From(expectedCodeDocument.GetHtmlDocument().GeneratedHtml);
                edits = SourceTextDiffer.GetMinimalTextChanges(beforeHtmlText, afterHtmlText, lineDiffOnly: false).Select(c => c.AsTextEdit(beforeHtmlText)).ToArray();
            }

            return(languageKind, edits);
        }
        protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
        {
            if (codeDocument == null)
            {
                throw new ArgumentNullException(nameof(codeDocument));
            }

            if (documentNode == null)
            {
                throw new ArgumentNullException(nameof(documentNode));
            }

            var @namespace = documentNode.FindPrimaryNamespace();
            var @class     = documentNode.FindPrimaryClass();

            if (@namespace == null || @class == null)
            {
                return;
            }

            var directives = documentNode.FindDirectiveReferences(ComponentPageDirective.Directive);

            if (directives.Count == 0)
            {
                return;
            }

            // We don't allow @page directives in imports
            for (var i = 0; i < directives.Count; i++)
            {
                var directive = directives[i];
                if (FileKinds.IsComponentImport(codeDocument.GetFileKind()) || directive.Node.IsImported())
                {
                    directive.Node.Diagnostics.Add(ComponentDiagnosticFactory.CreatePageDirective_CannotBeImported(directive.Node.Source.Value));
                }
            }

            // Insert the attributes 'on-top' of the class declaration, since classes don't directly support attributes.
            var index = 0;

            for (; index < @namespace.Children.Count; index++)
            {
                if (object.ReferenceEquals(@class, @namespace.Children[index]))
                {
                    break;
                }
            }

            for (var i = 0; i < directives.Count; i++)
            {
                var pageDirective = (DirectiveIntermediateNode)directives[i].Node;

                // The parser also adds errors for invalid syntax, we just need to not crash.
                var routeToken = pageDirective.Tokens.FirstOrDefault();

                if (routeToken != null &&
                    routeToken.Content.Length >= 3 &&
                    routeToken.Content[0] == '\"' &&
                    routeToken.Content[1] == '/' &&
                    routeToken.Content[routeToken.Content.Length - 1] == '\"')
                {
                    var template = new StringSegment(routeToken.Content, 1, routeToken.Content.Length - 2);
                    @namespace.Children.Insert(index++, new RouteAttributeExtensionNode(template));
                }
                else
                {
                    pageDirective.Diagnostics.Add(ComponentDiagnosticFactory.CreatePageDirective_MustSpecifyRoute(pageDirective.Source));
                }
            }
        }