Exemplo n.º 1
0
        public void GetCompletionAt_AtAttributeEdge_IndexerAttribute_ReturnsCompletionsWithoutSnippet()
        {
            // Arrange
            var tagHelper = TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly");

            tagHelper.TagMatchingRule(rule => rule.TagName = "test");
            tagHelper.SetTypeName("TestTagHelper");
            tagHelper.BindAttribute(attribute =>
            {
                attribute.Name = "int-val";
                attribute.SetPropertyName("IntVal");
                attribute.TypeName = ("System.Collections.Generic.IDictionary<System.String, System.Int32>");
                attribute.AsDictionary("int-val-", typeof(int).FullName);
            });
            var service      = new DefaultTagHelperCompletionService(RazorTagHelperCompletionService, HtmlFactsService, TagHelperFactsService);
            var codeDocument = CreateCodeDocument($"@addTagHelper *, TestAssembly{Environment.NewLine}<test />", tagHelper.Build());
            var sourceSpan   = new SourceSpan(35 + Environment.NewLine.Length, 0);

            // Act
            var completions = service.GetCompletionsAt(sourceSpan, codeDocument);

            // Assert
            Assert.Collection(
                completions,
                completion =>
            {
                Assert.Equal("int-val", completion.InsertText);
                Assert.Equal(InsertTextFormat.PlainText, completion.InsertTextFormat);
                Assert.Equal(new[] { "=" }, completion.CommitCharacters);
            },
                completion =>
            {
                Assert.Equal("int-val-", completion.InsertText);
                Assert.Equal(InsertTextFormat.PlainText, completion.InsertTextFormat);
                Assert.Equal(Array.Empty <string>(), completion.CommitCharacters);
            });
        }
Exemplo n.º 2
0
        public async Task Handle_ProvidesInjectOnIncomplete()
        {
            // Arrange
            var documentPath = "C:/path/to/document.razor";
            var builder      = TagHelperDescriptorBuilder.Create(ComponentMetadata.Component.TagHelperKind, "TestTagHelper", "TestAssembly");

            builder.TagMatchingRule(rule => rule.TagName = "Test");
            builder.SetTypeName("TestNamespace.TestTagHelper");
            var tagHelper        = builder.Build();
            var tagHelperContext = TagHelperDocumentContext.Create(prefix: string.Empty, new[] { tagHelper });
            var codeDocument     = CreateCodeDocument("@inje");

            codeDocument.SetTagHelperContext(tagHelperContext);
            var documentResolver   = CreateDocumentResolver(documentPath, codeDocument);
            var completionEndpoint = new RazorCompletionEndpoint(
                Dispatcher, documentResolver, CompletionFactsService, CompletionListCache, LoggerFactory);

            completionEndpoint.GetRegistration(ClientCapabilities);
            var request = new VSCompletionParamsBridge()
            {
                TextDocument = new TextDocumentIdentifier()
                {
                    Uri = new Uri(documentPath)
                },
                Position = new Position(0, 1),
                Context  = new VSInternalCompletionContext()
                {
                    TriggerKind = CompletionTriggerKind.TriggerForIncompleteCompletions,
                },
            };

            // Act
            var completionList = await Task.Run(() => completionEndpoint.Handle(request, default));

            // Assert
            Assert.Contains(completionList.Items, item => item.InsertText == "addTagHelper");
        }
        public void GetElementCompletions_TagHelperPrefixIsPrependedToTagHelperCompletions()
        {
            // Arrange
            var documentDescriptors = new[]
            {
                TagHelperDescriptorBuilder.Create("SuperLiTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli"))
                .Build(),
                TagHelperDescriptorBuilder.Create("LiTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li"))
                .Build(),
            };
            var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >()
            {
                ["th:superli"] = new HashSet <TagHelperDescriptor> {
                    documentDescriptors[0]
                },
                ["th:li"] = new HashSet <TagHelperDescriptor> {
                    documentDescriptors[1]
                },
                ["li"] = new HashSet <TagHelperDescriptor>(),
            });

            var existingCompletions = new[] { "li" };
            var completionContext   = BuildElementCompletionContext(
                documentDescriptors,
                existingCompletions,
                containingTagName: "ul",
                tagHelperPrefix: "th:");
            var service = CreateTagHelperCompletionFactsService();

            // Act
            var completions = service.GetElementCompletions(completionContext);

            // Assert
            AssertCompletionsAreEquivalent(expectedCompletions, completions);
        }
Exemplo n.º 4
0
        public void TagHelperAttributesAreLocatedAndAcceptChangesCorrectly(object editObject, object partialParseResultObject)
        {
            // Arrange
            var edit = (TestEdit)editObject;
            var partialParseResult = (PartialParseResultInternal)partialParseResultObject;
            var builder            = TagHelperDescriptorBuilder.Create("PTagHelper", "Test");

            builder.SetTypeName("PTagHelper");
            builder.TagMatchingRule(rule => rule.TagName = "p");
            builder.BindAttribute(attribute =>
            {
                attribute.Name     = "obj-attr";
                attribute.TypeName = typeof(object).FullName;
                attribute.SetPropertyName("ObjectAttribute");
            });
            builder.BindAttribute(attribute =>
            {
                attribute.Name     = "str-attr";
                attribute.TypeName = typeof(string).FullName;
                attribute.SetPropertyName("StringAttribute");
            });
            var descriptors    = new[] { builder.Build() };
            var projectEngine  = CreateProjectEngine(tagHelpers: descriptors);
            var sourceDocument = new TestRazorProjectItem("Index.cshtml")
            {
                Content = edit.OldSnapshot.GetText()
            };
            var codeDocument = projectEngine.Process(sourceDocument);
            var syntaxTree   = codeDocument.GetSyntaxTree();
            var parser       = new RazorSyntaxTreePartialParser(syntaxTree);

            // Act
            var(result, _) = parser.Parse(edit.Change);

            // Assert
            Assert.Equal(partialParseResult, result);
        }
Exemplo n.º 5
0
        public DefaultProjectSnapshotManagerProxyTest()
        {
            Workspace = TestWorkspace.Create();
            var projectWorkspaceState1 = new ProjectWorkspaceState(new[]
            {
                TagHelperDescriptorBuilder.Create("test1", "TestAssembly1").Build(),
            }, default);

            ProjectSnapshot1 = new DefaultProjectSnapshot(
                ProjectState.Create(
                    Workspace.Services,
                    new HostProject("/host/path/to/project1.csproj", RazorConfiguration.Default, "project1"),
                    projectWorkspaceState1));
            var projectWorkspaceState2 = new ProjectWorkspaceState(new[]
            {
                TagHelperDescriptorBuilder.Create("test2", "TestAssembly2").Build(),
            }, default);

            ProjectSnapshot2 = new DefaultProjectSnapshot(
                ProjectState.Create(
                    Workspace.Services,
                    new HostProject("/host/path/to/project2.csproj", RazorConfiguration.Default, "project2"),
                    projectWorkspaceState2));
        }
        public void GetElementCompletions_NewCompletionsForSchemaTagsNotInExistingCompletionsAreIgnored()
        {
            // Arrange
            var documentDescriptors = new[]
            {
                TagHelperDescriptorBuilder.Create("SuperLiTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli"))
                .Build(),
                TagHelperDescriptorBuilder.Create("LiTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li"))
                .TagOutputHint("strong")
                .Build(),
                TagHelperDescriptorBuilder.Create("DivTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div"))
                .Build(),
            };
            var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >()
            {
                ["li"] = new HashSet <TagHelperDescriptor> {
                    documentDescriptors[1]
                },
                ["superli"] = new HashSet <TagHelperDescriptor> {
                    documentDescriptors[0]
                },
            });

            var existingCompletions = new[] { "li" };
            var completionContext   = BuildElementCompletionContext(documentDescriptors, existingCompletions, containingTagName: "ul");
            var service             = CreateTagHelperCompletionFactsService();

            // Act
            var completions = service.GetElementCompletions(completionContext);

            // Assert
            AssertCompletionsAreEquivalent(expectedCompletions, completions);
        }
        public void GetElementCompletions_TagOutputHintDoesNotFallThroughToSchemaCheck()
        {
            // Arrange
            var documentDescriptors = new[]
            {
                TagHelperDescriptorBuilder.Create("MyTableTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("my-table"))
                .TagOutputHint("table")
                .Build(),
                TagHelperDescriptorBuilder.Create("MyTrTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("my-tr"))
                .TagOutputHint("tr")
                .Build(),
            };
            var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >()
            {
                ["my-table"] = new HashSet <TagHelperDescriptor> {
                    documentDescriptors[0]
                },
                ["table"] = new HashSet <TagHelperDescriptor>(),
            });

            var existingCompletions = new[] { "table" };
            var completionContext   = BuildElementCompletionContext(
                documentDescriptors,
                existingCompletions,
                containingTagName: "body",
                containingParentTagName: null);
            var service = CreateTagHelperCompletionFactsService();

            // Act
            var completions = service.GetElementCompletions(completionContext);

            // Assert
            AssertCompletionsAreEquivalent(expectedCompletions, completions);
        }
        public void GetAttributeCompletions_PossibleDescriptorsReturnUnboundRequiredAttributesWithExistingCompletions()
        {
            // Arrange
            var documentDescriptors = new[]
            {
                TagHelperDescriptorBuilder.Create("DivTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule
                                           .RequireTagName("div")
                                           .RequireAttributeDescriptor(attribute => attribute.Name("repeat")))
                .Build(),
                TagHelperDescriptorBuilder.Create("StyleTagHelper", "TestAssembly")
                .TagMatchingRuleDescriptor(rule => rule
                                           .RequireTagName("*")
                                           .RequireAttributeDescriptor(attribute => attribute.Name("class")))
                .Build(),
            };
            var expectedCompletions = AttributeCompletionResult.Create(new Dictionary <string, HashSet <BoundAttributeDescriptor> >()
            {
                ["class"]   = new HashSet <BoundAttributeDescriptor>(),
                ["onclick"] = new HashSet <BoundAttributeDescriptor>(),
                ["repeat"]  = new HashSet <BoundAttributeDescriptor>()
            });

            var existingCompletions = new[] { "onclick", "class" };
            var completionContext   = BuildAttributeCompletionContext(
                documentDescriptors,
                existingCompletions,
                currentTagName: "div");
            var service = CreateTagHelperCompletionFactsService();

            // Act
            var completions = service.GetAttributeCompletions(completionContext);

            // Assert
            AssertCompletionsAreEquivalent(expectedCompletions, completions);
        }
Exemplo n.º 9
0
        public ProjectStateGeneratedOutputTest()
        {
            HostProject = new HostProject(TestProjectData.SomeProject.FilePath, FallbackRazorConfiguration.MVC_2_0);
            HostProjectWithConfigurationChange = new HostProject(TestProjectData.SomeProject.FilePath, FallbackRazorConfiguration.MVC_1_0);

            var projectId = ProjectId.CreateNewId("Test");
            var solution  = Workspace.CurrentSolution.AddProject(ProjectInfo.Create(
                                                                     projectId,
                                                                     VersionStamp.Default,
                                                                     "Test",
                                                                     "Test",
                                                                     LanguageNames.CSharp,
                                                                     TestProjectData.SomeProject.FilePath));

            WorkspaceProject = solution.GetProject(projectId);

            SomeTagHelpers = new List <TagHelperDescriptor>();
            SomeTagHelpers.Add(TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());

            HostDocument = TestProjectData.SomeProjectFile1;

            Text       = SourceText.From("Hello, world!");
            TextLoader = () => Task.FromResult(TextAndVersion.Create(Text, VersionStamp.Create()));
        }
Exemplo n.º 10
0
    public void GetBinding_CaseSensitiveRule_CaseMismatch_ReturnsNull()
    {
        // Arrange
        var divTagHelper = TagHelperDescriptorBuilder.Create("DivTagHelper", "SomeAssembly")
                           .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div"))
                           .SetCaseSensitive()
                           .Build();
        var expectedDescriptors = new[] { divTagHelper };
        var expectedAttributes  = new[]
        {
            new KeyValuePair <string, string>("class", "something")
        };
        var tagHelperBinder = new TagHelperBinder("th:", expectedDescriptors);

        // Act
        var bindingResult = tagHelperBinder.GetBinding(
            tagName: "th:Div",
            attributes: expectedAttributes,
            parentTagName: "body",
            parentIsTagHelper: false);

        // Assert
        Assert.Null(bindingResult);
    }
        private TagHelperDescriptor CreateRefTagHelper()
        {
            var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.Ref.TagHelperKind, "Ref", ComponentsApi.AssemblyName);

            builder.Documentation = ComponentResources.RefTagHelper_Documentation;

            builder.Metadata.Add(ComponentMetadata.SpecialKindKey, ComponentMetadata.Ref.TagHelperKind);
            builder.Metadata.Add(TagHelperMetadata.Common.ClassifyAttributesOnly, bool.TrueString);
            builder.Metadata[TagHelperMetadata.Runtime.Name] = ComponentMetadata.Ref.RuntimeName;

            // WTE has a bug in 15.7p1 where a Tag Helper without a display-name that looks like
            // a C# property will crash trying to create the tooltips.
            builder.SetTypeName("Microsoft.AspNetCore.Components.Ref");

            builder.TagMatchingRule(rule =>
            {
                rule.TagName = "*";
                rule.Attribute(attribute =>
                {
                    attribute.Name = "ref";
                });
            });

            builder.BindAttribute(attribute =>
            {
                attribute.Documentation = ComponentResources.RefTagHelper_Documentation;
                attribute.Name          = "ref";

                // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                // a C# property will crash trying to create the tooltips.
                attribute.SetPropertyName("Ref");
                attribute.TypeName = typeof(object).FullName;
            });

            return(builder.Build());
        }
Exemplo n.º 12
0
        public ProjectStateTest()
        {
            HostProject = new HostProject(TestProjectData.SomeProject.FilePath, FallbackRazorConfiguration.MVC_2_0, TestProjectData.SomeProject.RootNamespace);
            HostProjectWithConfigurationChange = new HostProject(TestProjectData.SomeProject.FilePath, FallbackRazorConfiguration.MVC_1_0, TestProjectData.SomeProject.RootNamespace);
            ProjectWorkspaceState = new ProjectWorkspaceState(new[]
            {
                TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly").Build(),
            });

            SomeTagHelpers = new List <TagHelperDescriptor>();
            SomeTagHelpers.Add(TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());

            Documents = new HostDocument[]
            {
                TestProjectData.SomeProjectFile1,
                TestProjectData.SomeProjectFile2,

                // linked file
                TestProjectData.AnotherProjectNestedFile3,
            };

            Text       = SourceText.From("Hello, world!");
            TextLoader = () => Task.FromResult(TextAndVersion.Create(Text, VersionStamp.Create()));
        }
Exemplo n.º 13
0
        public void CreateDescriptor_ForAsyncViewComponentWithInvokeInBaseType_Works()
        {
            // Arrange
            var testCompilation = TestCompilation.Create(_assembly);
            var factory         = new ViewComponentTagHelperDescriptorFactory(testCompilation);

            var expectedDescriptor = TagHelperDescriptorBuilder.Create(
                ViewComponentTagHelperConventions.Kind,
                "__Generated__AsyncDerivedViewComponentTagHelper",
                typeof(AsyncDerivedViewComponent).Assembly.GetName().Name)
                                     .TypeName("__Generated__AsyncDerivedViewComponentTagHelper")
                                     .DisplayName("AsyncDerivedViewComponentTagHelper")
                                     .TagMatchingRuleDescriptor(rule => rule.RequireTagName("vc:async-derived"))
                                     .AddMetadata(ViewComponentTagHelperMetadata.Name, "AsyncDerived")
                                     .Build();

            var viewComponent = testCompilation.GetTypeByMetadataName(typeof(AsyncDerivedViewComponent).FullName);

            // Act
            var descriptor = factory.CreateDescriptor(viewComponent);

            // Assert
            Assert.Equal(expectedDescriptor, descriptor, TagHelperDescriptorComparer.CaseSensitive);
        }
        private static TagHelperDescriptor CreateTagHelperDescriptor(
            string tagName,
            string typeName,
            string assemblyName,
            IEnumerable <Action <BoundAttributeDescriptorBuilder> > attributes = null)
        {
            var builder = TagHelperDescriptorBuilder.Create(typeName, assemblyName);

            builder.TypeName(typeName);

            if (attributes != null)
            {
                foreach (var attributeBuilder in attributes)
                {
                    builder.BindAttribute(attributeBuilder);
                }
            }

            builder.TagMatchingRule(ruleBuilder => ruleBuilder.RequireTagName(tagName));

            var descriptor = builder.Build();

            return(descriptor);
        }
        public DefaultVisualStudioDocumentTrackerTest()
        {
            RazorCoreContentType = Mock.Of <IContentType>(c => c.IsOfType(RazorLanguage.ContentType) == true);
            TextBuffer           = Mock.Of <ITextBuffer>(b => b.ContentType == RazorCoreContentType);

            FilePath      = TestProjectData.SomeProjectFile1.FilePath;
            ProjectPath   = TestProjectData.SomeProject.FilePath;
            RootNamespace = TestProjectData.SomeProject.RootNamespace;

            ImportDocumentManager   = Mock.Of <ImportDocumentManager>();
            WorkspaceEditorSettings = new DefaultWorkspaceEditorSettings(Mock.Of <ForegroundDispatcher>(), Mock.Of <EditorSettingsManager>());

            SomeTagHelpers = new List <TagHelperDescriptor>()
            {
                TagHelperDescriptorBuilder.Create("test", "test").Build(),
            };

            ProjectManager = new TestProjectSnapshotManager(Dispatcher, Workspace)
            {
                AllowNotifyListeners = true
            };

            HostProject        = new HostProject(ProjectPath, FallbackRazorConfiguration.MVC_2_1, RootNamespace);
            UpdatedHostProject = new HostProject(ProjectPath, FallbackRazorConfiguration.MVC_2_0, RootNamespace);
            OtherHostProject   = new HostProject(TestProjectData.AnotherProject.FilePath, FallbackRazorConfiguration.MVC_2_0, TestProjectData.AnotherProject.RootNamespace);

            DocumentTracker = new DefaultVisualStudioDocumentTracker(
                Dispatcher,
                FilePath,
                ProjectPath,
                ProjectManager,
                WorkspaceEditorSettings,
                Workspace,
                TextBuffer,
                ImportDocumentManager);
        }
        public void HaveTagHelpersChanged_TagHelpersUpdated_ReturnsTrue()
        {
            // Arrange
            var hostProject      = new HostProject("Test1.csproj", RazorConfiguration.Default);
            var workspaceProject = GetWorkspaceProject("Test1");
            var original         = new DefaultProjectSnapshot(hostProject, workspaceProject);

            var anotherProject = GetWorkspaceProject("Test1");
            var update         = new ProjectSnapshotUpdateContext("Test1.csproj", hostProject, anotherProject, VersionStamp.Default)
            {
                TagHelpers = new[]
                {
                    TagHelperDescriptorBuilder.Create("One", "TestAssembly").Build(),
                    TagHelperDescriptorBuilder.Create("Two", "TestAssembly").Build(),
                },
            };
            var snapshot = original.WithComputedUpdate(update);

            // Act
            var result = snapshot.HaveTagHelpersChanged(original);

            // Assert
            Assert.True(result);
        }
        private List <TagHelperDescriptor> CreateComponentBindTagHelpers(ICollection <TagHelperDescriptor> tagHelpers)
        {
            var results = new List <TagHelperDescriptor>();

            foreach (var tagHelper in tagHelpers)
            {
                if (!tagHelper.IsComponentTagHelper())
                {
                    continue;
                }

                // We want to create a 'bind' tag helper everywhere we see a pair of properties like `Foo`, `FooChanged`
                // where `FooChanged` is a delegate and `Foo` is not.
                //
                // The easiest way to figure this out without a lot of backtracking is to look for `FooChanged` and then
                // try to find a matching "Foo".
                //
                // We also look for a corresponding FooExpression attribute, though its presence is optional.
                for (var i = 0; i < tagHelper.BoundAttributes.Count; i++)
                {
                    var changeAttribute = tagHelper.BoundAttributes[i];
                    if (!changeAttribute.Name.EndsWith("Changed", StringComparison.Ordinal) ||

                        // Allow the ValueChanged attribute to be a delegate or EventCallback<>.
                        //
                        // We assume that the Delegate or EventCallback<> has a matching type, and the C# compiler will help
                        // you figure figure it out if you did it wrongly.
                        (!changeAttribute.IsDelegateProperty() && !changeAttribute.IsEventCallbackProperty()))
                    {
                        continue;
                    }

                    BoundAttributeDescriptor valueAttribute      = null;
                    BoundAttributeDescriptor expressionAttribute = null;
                    var valueAttributeName      = changeAttribute.Name.Substring(0, changeAttribute.Name.Length - "Changed".Length);
                    var expressionAttributeName = valueAttributeName + "Expression";
                    for (var j = 0; j < tagHelper.BoundAttributes.Count; j++)
                    {
                        if (tagHelper.BoundAttributes[j].Name == valueAttributeName)
                        {
                            valueAttribute = tagHelper.BoundAttributes[j];
                        }

                        if (tagHelper.BoundAttributes[j].Name == expressionAttributeName)
                        {
                            expressionAttribute = tagHelper.BoundAttributes[j];
                        }

                        if (valueAttribute != null && expressionAttribute != null)
                        {
                            // We found both, so we can stop looking now
                            break;
                        }
                    }

                    if (valueAttribute == null)
                    {
                        // No matching attribute found.
                        continue;
                    }

                    var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.Bind.TagHelperKind, tagHelper.Name, tagHelper.AssemblyName);
                    builder.DisplayName   = tagHelper.DisplayName;
                    builder.CaseSensitive = true;
                    builder.Documentation = string.Format(
                        CultureInfo.CurrentCulture,
                        ComponentResources.BindTagHelper_Component_Documentation,
                        valueAttribute.Name,
                        changeAttribute.Name);

                    builder.Metadata.Add(ComponentMetadata.SpecialKindKey, ComponentMetadata.Bind.TagHelperKind);
                    builder.Metadata[TagHelperMetadata.Runtime.Name]         = ComponentMetadata.Bind.RuntimeName;
                    builder.Metadata[ComponentMetadata.Bind.ValueAttribute]  = valueAttribute.Name;
                    builder.Metadata[ComponentMetadata.Bind.ChangeAttribute] = changeAttribute.Name;

                    if (expressionAttribute != null)
                    {
                        builder.Metadata[ComponentMetadata.Bind.ExpressionAttribute] = expressionAttribute.Name;
                    }

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the toolips.
                    builder.SetTypeName(tagHelper.GetTypeName());

                    // Match the component and attribute name
                    builder.TagMatchingRule(rule =>
                    {
                        rule.TagName = tagHelper.TagMatchingRules.Single().TagName;
                        rule.Attribute(attribute =>
                        {
                            attribute.Name = "@bind-" + valueAttribute.Name;
                            attribute.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                            attribute.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                        });
                    });

                    builder.BindAttribute(attribute =>
                    {
                        attribute.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                        attribute.Documentation = string.Format(
                            CultureInfo.CurrentCulture,
                            ComponentResources.BindTagHelper_Component_Documentation,
                            valueAttribute.Name,
                            changeAttribute.Name);

                        attribute.Name     = "@bind-" + valueAttribute.Name;
                        attribute.TypeName = changeAttribute.TypeName;
                        attribute.IsEnum   = valueAttribute.IsEnum;

                        // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                        // a C# property will crash trying to create the toolips.
                        attribute.SetPropertyName(valueAttribute.GetPropertyName());
                    });

                    if (tagHelper.IsComponentFullyQualifiedNameMatch())
                    {
                        builder.Metadata[ComponentMetadata.Component.NameMatchKey] = ComponentMetadata.Component.FullyQualifiedNameMatch;
                    }

                    results.Add(builder.Build());
                }
            }

            return(results);
        }
        private List <TagHelperDescriptor> CreateElementBindTagHelpers(List <ElementBindData> data)
        {
            var results = new List <TagHelperDescriptor>();

            for (var i = 0; i < data.Count; i++)
            {
                var entry = data[i];

                var name          = entry.Suffix == null ? "Bind" : "Bind_" + entry.Suffix;
                var attributeName = entry.Suffix == null ? "@bind" : "@bind-" + entry.Suffix;

                var formatName          = entry.Suffix == null ? "Format_" + entry.ValueAttribute : "Format_" + entry.Suffix;
                var formatAttributeName = entry.Suffix == null ? "format-" + entry.ValueAttribute : "format-" + entry.Suffix;

                var eventName = entry.Suffix == null ? "Event_" + entry.ValueAttribute : "Event_" + entry.Suffix;

                var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.Bind.TagHelperKind, name, ComponentsApi.AssemblyName);
                builder.CaseSensitive = true;
                builder.Documentation = string.Format(
                    CultureInfo.CurrentCulture,
                    ComponentResources.BindTagHelper_Element_Documentation,
                    entry.ValueAttribute,
                    entry.ChangeAttribute);

                builder.Metadata.Add(ComponentMetadata.SpecialKindKey, ComponentMetadata.Bind.TagHelperKind);
                builder.Metadata.Add(TagHelperMetadata.Common.ClassifyAttributesOnly, bool.TrueString);
                builder.Metadata[TagHelperMetadata.Runtime.Name]            = ComponentMetadata.Bind.RuntimeName;
                builder.Metadata[ComponentMetadata.Bind.ValueAttribute]     = entry.ValueAttribute;
                builder.Metadata[ComponentMetadata.Bind.ChangeAttribute]    = entry.ChangeAttribute;
                builder.Metadata[ComponentMetadata.Bind.IsInvariantCulture] = entry.IsInvariantCulture ? bool.TrueString : bool.FalseString;
                builder.Metadata[ComponentMetadata.Bind.Format]             = entry.Format;

                if (entry.TypeAttribute != null)
                {
                    // For entries that map to the <input /> element, we need to be able to know
                    // the difference between <input /> and <input type="text" .../> for which we
                    // want to use the same attributes.
                    //
                    // We provide a tag helper for <input /> that should match all input elements,
                    // but we only want it to be used when a more specific one is used.
                    //
                    // Therefore we use this metadata to know which one is more specific when two
                    // tag helpers match.
                    builder.Metadata[ComponentMetadata.Bind.TypeAttribute] = entry.TypeAttribute;
                }

                // WTE has a bug in 15.7p1 where a Tag Helper without a display-name that looks like
                // a C# property will crash trying to create the toolips.
                builder.SetTypeName(entry.TypeName);

                builder.TagMatchingRule(rule =>
                {
                    rule.TagName = entry.Element;
                    if (entry.TypeAttribute != null)
                    {
                        rule.Attribute(a =>
                        {
                            a.Name = "type";
                            a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                            a.Value = entry.TypeAttribute;
                            a.ValueComparisonMode = RequiredAttributeDescriptor.ValueComparisonMode.FullMatch;
                        });
                    }

                    rule.Attribute(a =>
                    {
                        a.Name = attributeName;
                        a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                        a.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                    });
                });

                builder.BindAttribute(a =>
                {
                    a.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                    a.Documentation = string.Format(
                        CultureInfo.CurrentCulture,
                        ComponentResources.BindTagHelper_Element_Documentation,
                        entry.ValueAttribute,
                        entry.ChangeAttribute);

                    a.Name     = attributeName;
                    a.TypeName = typeof(object).FullName;

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the toolips.
                    a.SetPropertyName(name);

                    a.BindAttributeParameter(parameter =>
                    {
                        parameter.Name          = "format";
                        parameter.TypeName      = typeof(string).FullName;
                        parameter.Documentation = string.Format(CultureInfo.CurrentCulture, ComponentResources.BindTagHelper_Element_Format_Documentation, attributeName);

                        parameter.SetPropertyName(formatName);
                    });

                    a.BindAttributeParameter(parameter =>
                    {
                        parameter.Name          = "event";
                        parameter.TypeName      = typeof(string).FullName;
                        parameter.Documentation = string.Format(CultureInfo.CurrentCulture, ComponentResources.BindTagHelper_Element_Event_Documentation, attributeName);

                        parameter.SetPropertyName(eventName);
                    });

                    a.BindAttributeParameter(parameter =>
                    {
                        parameter.Name          = "culture";
                        parameter.TypeName      = typeof(CultureInfo).FullName;
                        parameter.Documentation = ComponentResources.BindTagHelper_Element_Culture_Documentation;

                        parameter.SetPropertyName("Culture");
                    });
                });

                // This is no longer supported. This is just here so we can add a diagnostic later on when this matches.
                builder.BindAttribute(attribute =>
                {
                    attribute.Name          = formatAttributeName;
                    attribute.TypeName      = "System.String";
                    attribute.Documentation = string.Format(CultureInfo.CurrentCulture, ComponentResources.BindTagHelper_Element_Format_Documentation, attributeName);

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the toolips.
                    attribute.SetPropertyName(formatName);
                });

                results.Add(builder.Build());
            }

            return(results);
        }
        private TagHelperDescriptor CreateFallbackBindTagHelper()
        {
            var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.Bind.TagHelperKind, "Bind", ComponentsApi.AssemblyName);

            builder.CaseSensitive = true;
            builder.Documentation = ComponentResources.BindTagHelper_Fallback_Documentation;

            builder.Metadata.Add(ComponentMetadata.SpecialKindKey, ComponentMetadata.Bind.TagHelperKind);
            builder.Metadata.Add(TagHelperMetadata.Common.ClassifyAttributesOnly, bool.TrueString);
            builder.Metadata[TagHelperMetadata.Runtime.Name]     = ComponentMetadata.Bind.RuntimeName;
            builder.Metadata[ComponentMetadata.Bind.FallbackKey] = bool.TrueString;

            // WTE has a bug in 15.7p1 where a Tag Helper without a display-name that looks like
            // a C# property will crash trying to create the toolips.
            builder.SetTypeName("Microsoft.AspNetCore.Components.Bind");

            builder.TagMatchingRule(rule =>
            {
                rule.TagName = "*";
                rule.Attribute(attribute =>
                {
                    attribute.Name = "@bind-";
                    attribute.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch;
                    attribute.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                });
            });

            builder.BindAttribute(attribute =>
            {
                attribute.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                attribute.Documentation = ComponentResources.BindTagHelper_Fallback_Documentation;

                var attributeName = "@bind-...";
                attribute.Name    = attributeName;
                attribute.AsDictionary("@bind-", typeof(object).FullName);

                // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                // a C# property will crash trying to create the toolips.
                attribute.SetPropertyName("Bind");
                attribute.TypeName = "System.Collections.Generic.Dictionary<string, object>";

                attribute.BindAttributeParameter(parameter =>
                {
                    parameter.Name          = "format";
                    parameter.TypeName      = typeof(string).FullName;
                    parameter.Documentation = ComponentResources.BindTagHelper_Fallback_Format_Documentation;

                    parameter.SetPropertyName("Format");
                });

                attribute.BindAttributeParameter(parameter =>
                {
                    parameter.Name          = "event";
                    parameter.TypeName      = typeof(string).FullName;
                    parameter.Documentation = string.Format(CultureInfo.CurrentCulture, ComponentResources.BindTagHelper_Fallback_Event_Documentation, attributeName);

                    parameter.SetPropertyName("Event");
                });

                attribute.BindAttributeParameter(parameter =>
                {
                    parameter.Name          = "culture";
                    parameter.TypeName      = typeof(CultureInfo).FullName;
                    parameter.Documentation = ComponentResources.BindTagHelper_Element_Culture_Documentation;

                    parameter.SetPropertyName("Culture");
                });
            });

            return(builder.Build());
        }
        public void DefaultTagHelperOptimizationPass_Execute_ReplacesChildren()
        {
            // Arrange
            var codeDocument = CreateDocument(@"
@addTagHelper TestTagHelper, TestAssembly
<p foo=""17"" attr=""value"">");

            var tagHelpers = new[]
            {
                TagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
                .TypeName("TestTagHelper")
                .BoundAttributeDescriptor(attribute => attribute
                                          .Name("Foo")
                                          .TypeName("System.Int32")
                                          .PropertyName("FooProp"))
                .TagMatchingRuleDescriptor(rule => rule.RequireTagName("p"))
                .Build()
            };

            var engine = CreateEngine(tagHelpers);
            var pass   = new DefaultTagHelperOptimizationPass()
            {
                Engine = engine
            };

            var irDocument = CreateIRDocument(engine, codeDocument);

            // Act
            pass.Execute(codeDocument, irDocument);

            // Assert
            var @class = irDocument.FindPrimaryClass();

            Assert.IsType <DefaultTagHelperRuntimeIntermediateNode>(@class.Children[0]);

            var fieldDeclaration = Assert.IsType <FieldDeclarationIntermediateNode>(@class.Children[1]);

            Assert.Equal(bool.TrueString, fieldDeclaration.Annotations[CommonAnnotations.DefaultTagHelperExtension.TagHelperField]);
            Assert.Equal("__TestTagHelper", fieldDeclaration.FieldName);
            Assert.Equal("global::TestTagHelper", fieldDeclaration.FieldType);
            Assert.Equal("private", fieldDeclaration.Modifiers.First());

            var tagHelper = FindTagHelperNode(irDocument);

            Assert.Equal(5, tagHelper.Children.Count);

            var body = Assert.IsType <DefaultTagHelperBodyIntermediateNode>(tagHelper.Children[0]);

            Assert.Equal("p", body.TagName);
            Assert.Equal(TagMode.StartTagAndEndTag, body.TagMode);

            var create = Assert.IsType <DefaultTagHelperCreateIntermediateNode>(tagHelper.Children[1]);

            Assert.Equal("__TestTagHelper", create.FieldName);
            Assert.Equal("TestTagHelper", create.TypeName);
            Assert.Equal(tagHelpers[0], create.TagHelper, TagHelperDescriptorComparer.Default);

            var property = Assert.IsType <DefaultTagHelperPropertyIntermediateNode>(tagHelper.Children[2]);

            Assert.Equal("foo", property.AttributeName);
            Assert.Equal(AttributeStructure.DoubleQuotes, property.AttributeStructure);
            Assert.Equal(tagHelpers[0].BoundAttributes[0], property.BoundAttribute, BoundAttributeDescriptorComparer.Default);
            Assert.Equal("__TestTagHelper", property.FieldName);
            Assert.False(property.IsIndexerNameMatch);
            Assert.Equal("FooProp", property.PropertyName);
            Assert.Equal(tagHelpers[0], property.TagHelper, TagHelperDescriptorComparer.Default);

            var htmlAttribute = Assert.IsType <DefaultTagHelperHtmlAttributeIntermediateNode>(tagHelper.Children[3]);

            Assert.Equal("attr", htmlAttribute.AttributeName);
            Assert.Equal(AttributeStructure.DoubleQuotes, htmlAttribute.AttributeStructure);

            Assert.IsType <DefaultTagHelperExecuteIntermediateNode>(tagHelper.Children[4]);
        }
Exemplo n.º 21
0
        private TagHelperDescriptor CreateDescriptor(INamedTypeSymbol type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            var typeName     = type.ToDisplayString(FullNameTypeDisplayFormat);
            var assemblyName = type.ContainingAssembly.Identity.Name;

            var builder = TagHelperDescriptorBuilder.Create(ComponentTagHelperKind, typeName, assemblyName);

            builder.SetTypeName(typeName);

            // This opts out this 'component' tag helper for any processing that's specific to the default
            // Razor ITagHelper runtime.
            builder.Metadata[TagHelperMetadata.Runtime.Name] = "Blazor.IComponent";

            var xml = type.GetDocumentationCommentXml();

            if (!string.IsNullOrEmpty(xml))
            {
                builder.Documentation = xml;
            }

            // Components have very simple matching rules. The type name (short) matches the tag name.
            builder.TagMatchingRule(r => r.TagName = type.Name);

            foreach (var property in GetVisibleProperties(type))
            {
                if (property.kind == PropertyKind.Ignored)
                {
                    continue;
                }

                builder.BindAttribute(pb =>
                {
                    pb.Name     = property.property.Name;
                    pb.TypeName = property.property.Type.ToDisplayString(FullNameTypeDisplayFormat);
                    pb.SetPropertyName(property.property.Name);

                    if (property.kind == PropertyKind.Enum)
                    {
                        pb.IsEnum = true;
                    }

                    if (property.kind == PropertyKind.Delegate)
                    {
                        pb.Metadata.Add(DelegateSignatureMetadata, bool.TrueString);
                    }

                    xml = property.property.GetDocumentationCommentXml();
                    if (!string.IsNullOrEmpty(xml))
                    {
                        pb.Documentation = xml;
                    }
                });
            }

            var descriptor = builder.Build();

            return(descriptor);
        }
Exemplo n.º 22
0
        private List <TagHelperDescriptor> CreateComponentBindTagHelpers(ICollection <TagHelperDescriptor> tagHelpers)
        {
            var results = new List <TagHelperDescriptor>();

            foreach (var tagHelper in tagHelpers)
            {
                if (!tagHelper.IsComponentTagHelper())
                {
                    continue;
                }

                // We want to create a 'bind' tag helper everywhere we see a pair of properties like `Foo`, `FooChanged`
                // where `FooChanged` is a delegate and `Foo` is not.
                //
                // The easiest way to figure this out without a lot of backtracking is to look for `FooChanged` and then
                // try to find a matching "Foo".
                for (var i = 0; i < tagHelper.BoundAttributes.Count; i++)
                {
                    var changeAttribute = tagHelper.BoundAttributes[i];
                    if (!changeAttribute.Name.EndsWith("Changed") || !changeAttribute.IsDelegateProperty())
                    {
                        continue;
                    }

                    BoundAttributeDescriptor valueAttribute = null;
                    var valueAttributeName = changeAttribute.Name.Substring(0, changeAttribute.Name.Length - "Changed".Length);
                    for (var j = 0; j < tagHelper.BoundAttributes.Count; j++)
                    {
                        if (tagHelper.BoundAttributes[j].Name == valueAttributeName && !tagHelper.BoundAttributes[j].IsDelegateProperty())
                        {
                            valueAttribute = tagHelper.BoundAttributes[j];
                            break;
                        }
                    }

                    if (valueAttribute == null)
                    {
                        // No matching attribute found.
                        continue;
                    }

                    var builder = TagHelperDescriptorBuilder.Create(BlazorMetadata.Bind.TagHelperKind, tagHelper.Name, tagHelper.AssemblyName);
                    builder.DisplayName   = tagHelper.DisplayName;
                    builder.Documentation = string.Format(
                        Resources.BindTagHelper_Component_Documentation,
                        valueAttribute.Name,
                        changeAttribute.Name);

                    builder.Metadata.Add(BlazorMetadata.SpecialKindKey, BlazorMetadata.Bind.TagHelperKind);
                    builder.Metadata[TagHelperMetadata.Runtime.Name]      = BlazorMetadata.Bind.RuntimeName;
                    builder.Metadata[BlazorMetadata.Bind.ValueAttribute]  = valueAttribute.Name;
                    builder.Metadata[BlazorMetadata.Bind.ChangeAttribute] = changeAttribute.Name;

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the toolips.
                    builder.SetTypeName(tagHelper.GetTypeName());

                    // Match the component and attribute name
                    builder.TagMatchingRule(rule =>
                    {
                        rule.TagName = tagHelper.TagMatchingRules.Single().TagName;
                        rule.Attribute(attribute =>
                        {
                            attribute.Name = "bind-" + valueAttribute.Name;
                            attribute.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                        });
                    });

                    builder.BindAttribute(attribute =>
                    {
                        attribute.Documentation = string.Format(
                            Resources.BindTagHelper_Component_Documentation,
                            valueAttribute.Name,
                            changeAttribute.Name);

                        attribute.Name     = "bind-" + valueAttribute.Name;
                        attribute.TypeName = valueAttribute.TypeName;
                        attribute.IsEnum   = valueAttribute.IsEnum;

                        // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                        // a C# property will crash trying to create the toolips.
                        attribute.SetPropertyName(valueAttribute.GetPropertyName());
                    });

                    results.Add(builder.Build());
                }
            }

            return(results);
        }
        public TagHelperServiceTestBase()
        {
            var builder1 = TagHelperDescriptorBuilder.Create("Test1TagHelper", "TestAssembly");

            builder1.TagMatchingRule(rule => rule.TagName = "test1");
            builder1.SetTypeName("Test1TagHelper");
            builder1.BindAttribute(attribute =>
            {
                attribute.Name = "bool-val";
                attribute.SetPropertyName("BoolVal");
                attribute.TypeName = typeof(bool).FullName;
            });
            builder1.BindAttribute(attribute =>
            {
                attribute.Name = "int-val";
                attribute.SetPropertyName("IntVal");
                attribute.TypeName = typeof(int).FullName;
            });

            var builder2 = TagHelperDescriptorBuilder.Create("Test2TagHelper", "TestAssembly");

            builder2.TagMatchingRule(rule => rule.TagName = "test2");
            builder2.SetTypeName("Test2TagHelper");
            builder2.BindAttribute(attribute =>
            {
                attribute.Name = "bool-val";
                attribute.SetPropertyName("BoolVal");
                attribute.TypeName = typeof(bool).FullName;
            });
            builder2.BindAttribute(attribute =>
            {
                attribute.Name = "int-val";
                attribute.SetPropertyName("IntVal");
                attribute.TypeName = typeof(int).FullName;
            });

            var builder3 = TagHelperDescriptorBuilder.Create(ComponentMetadata.Component.TagHelperKind, "Component1TagHelper", "TestAssembly");

            builder3.TagMatchingRule(rule => rule.TagName = "Component1");
            builder3.SetTypeName("Component1");
            builder3.Metadata[ComponentMetadata.Component.NameMatchKey] = ComponentMetadata.Component.FullyQualifiedNameMatch;
            builder3.BindAttribute(attribute =>
            {
                attribute.Name = "bool-val";
                attribute.SetPropertyName("BoolVal");
                attribute.TypeName = typeof(bool).FullName;
            });
            builder3.BindAttribute(attribute =>
            {
                attribute.Name = "int-val";
                attribute.SetPropertyName("IntVal");
                attribute.TypeName = typeof(int).FullName;
            });

            var directiveAttribute1 = TagHelperDescriptorBuilder.Create(ComponentMetadata.Component.TagHelperKind, "TestDirectiveAttribute", "TestAssembly");

            directiveAttribute1.TagMatchingRule(rule =>
            {
                rule.TagName = "*";
                rule.RequireAttributeDescriptor(b =>
                {
                    b.Name = "@test";
                    b.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch;
                });
            });
            directiveAttribute1.TagMatchingRule(rule =>
            {
                rule.TagName = "*";
                rule.RequireAttributeDescriptor(b =>
                {
                    b.Name = "@test";
                    b.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                });
            });
            directiveAttribute1.BindAttribute(attribute =>
            {
                attribute.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                attribute.Name = "@test";
                attribute.SetPropertyName("Test");
                attribute.TypeName = typeof(string).FullName;

                attribute.BindAttributeParameter(parameter =>
                {
                    parameter.Name     = "something";
                    parameter.TypeName = typeof(string).FullName;

                    parameter.SetPropertyName("Something");
                });
            });
            directiveAttribute1.Metadata[TagHelperMetadata.Common.ClassifyAttributesOnly] = bool.TrueString;
            directiveAttribute1.Metadata[ComponentMetadata.Component.NameMatchKey]        = ComponentMetadata.Component.FullyQualifiedNameMatch;
            directiveAttribute1.SetTypeName("TestDirectiveAttribute");

            var directiveAttribute2 = TagHelperDescriptorBuilder.Create(ComponentMetadata.Component.TagHelperKind, "MinimizedDirectiveAttribute", "TestAssembly");

            directiveAttribute2.TagMatchingRule(rule =>
            {
                rule.TagName = "*";
                rule.RequireAttributeDescriptor(b =>
                {
                    b.Name = "@minimized";
                    b.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.PrefixMatch;
                });
            });
            directiveAttribute2.TagMatchingRule(rule =>
            {
                rule.TagName = "*";
                rule.RequireAttributeDescriptor(b =>
                {
                    b.Name = "@minimized";
                    b.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                });
            });
            directiveAttribute2.BindAttribute(attribute =>
            {
                attribute.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                attribute.Name = "@minimized";
                attribute.SetPropertyName("Minimized");
                attribute.TypeName = typeof(bool).FullName;

                attribute.BindAttributeParameter(parameter =>
                {
                    parameter.Name     = "something";
                    parameter.TypeName = typeof(string).FullName;

                    parameter.SetPropertyName("Something");
                });
            });
            directiveAttribute2.Metadata[TagHelperMetadata.Common.ClassifyAttributesOnly] = bool.TrueString;
            directiveAttribute2.Metadata[ComponentMetadata.Component.NameMatchKey]        = ComponentMetadata.Component.FullyQualifiedNameMatch;
            directiveAttribute2.SetTypeName("TestDirectiveAttribute");

            DefaultTagHelpers = new[] { builder1.Build(), builder2.Build(), builder3.Build(), directiveAttribute1.Build(), directiveAttribute2.Build() };

            HtmlFactsService                = new DefaultHtmlFactsService();
            TagHelperFactsService           = new DefaultTagHelperFactsService();
            RazorTagHelperCompletionService = new DefaultRazorTagHelperCompletionService(TagHelperFactsService);
        }
        public DefaultProjectSnapshotManagerTest()
        {
            // Force VB and C# to Load
            GC.KeepAlive(typeof(Microsoft.CodeAnalysis.CSharp.SyntaxFactory));
            GC.KeepAlive(typeof(Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory));

            TagHelperResolver = new TestTagHelperResolver();

            Documents = new HostDocument[]
            {
                TestProjectData.SomeProjectFile1,
                TestProjectData.SomeProjectFile2,

                // linked file
                TestProjectData.AnotherProjectNestedFile3,

                TestProjectData.SomeProjectComponentFile1,
                TestProjectData.SomeProjectComponentFile2,
            };

            HostProject = new HostProject(TestProjectData.SomeProject.FilePath, FallbackRazorConfiguration.MVC_2_0);
            HostProjectWithConfigurationChange = new HostProject(TestProjectData.SomeProject.FilePath, FallbackRazorConfiguration.MVC_1_0);

            ProjectManager = new TestProjectSnapshotManager(Dispatcher, Enumerable.Empty <ProjectSnapshotChangeTrigger>(), Workspace);

            var projectId = ProjectId.CreateNewId("Test");
            var solution  = Workspace.CurrentSolution.AddProject(ProjectInfo.Create(
                                                                     projectId,
                                                                     VersionStamp.Default,
                                                                     "Test",
                                                                     "Test",
                                                                     LanguageNames.CSharp,
                                                                     TestProjectData.SomeProject.FilePath));

            WorkspaceProject = solution.GetProject(projectId);

            var vbProjectId = ProjectId.CreateNewId("VB");

            solution = solution.AddProject(ProjectInfo.Create(
                                               vbProjectId,
                                               VersionStamp.Default,
                                               "VB",
                                               "VB",
                                               LanguageNames.VisualBasic,
                                               "VB.vbproj"));
            VBWorkspaceProject = solution.GetProject(vbProjectId);

            var projectWithoutFilePathId = ProjectId.CreateNewId("NoFile");

            solution = solution.AddProject(ProjectInfo.Create(
                                               projectWithoutFilePathId,
                                               VersionStamp.Default,
                                               "NoFile",
                                               "NoFile",
                                               LanguageNames.CSharp));
            WorkspaceProjectWithoutFilePath = solution.GetProject(projectWithoutFilePathId);

            // Approximates a project with multi-targeting
            var projectIdWithDifferentTfm = ProjectId.CreateNewId("TestWithDifferentTfm");

            solution = Workspace.CurrentSolution.AddProject(ProjectInfo.Create(
                                                                projectIdWithDifferentTfm,
                                                                VersionStamp.Default,
                                                                "Test (Different TFM)",
                                                                "Test",
                                                                LanguageNames.CSharp,
                                                                TestProjectData.SomeProject.FilePath));
            WorkspaceProjectWithDifferentTfm = solution.GetProject(projectIdWithDifferentTfm);

            SomeTagHelpers = TagHelperResolver.TagHelpers;
            SomeTagHelpers.Add(TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());

            SourceText = SourceText.From("Hello world");
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType != JsonToken.StartObject)
            {
                return(null);
            }

            var descriptor       = JObject.Load(reader);
            var descriptorKind   = descriptor[nameof(TagHelperDescriptor.Kind)].Value <string>();
            var typeName         = descriptor[nameof(TagHelperDescriptor.Name)].Value <string>();
            var assemblyName     = descriptor[nameof(TagHelperDescriptor.AssemblyName)].Value <string>();
            var tagMatchingRules = descriptor[nameof(TagHelperDescriptor.TagMatchingRules)].Value <JArray>();
            var boundAttributes  = descriptor[nameof(TagHelperDescriptor.BoundAttributes)].Value <JArray>();
            var childTags        = descriptor[nameof(TagHelperDescriptor.AllowedChildTags)].Value <JArray>();
            var documentation    = descriptor[nameof(TagHelperDescriptor.Documentation)].Value <string>();
            var tagOutputHint    = descriptor[nameof(TagHelperDescriptor.TagOutputHint)].Value <string>();
            var caseSensitive    = descriptor[nameof(TagHelperDescriptor.CaseSensitive)].Value <bool>();
            var diagnostics      = descriptor[nameof(TagHelperDescriptor.Diagnostics)].Value <JArray>();
            var metadata         = descriptor[nameof(TagHelperDescriptor.Metadata)].Value <JObject>();

            var builder = TagHelperDescriptorBuilder.Create(descriptorKind, typeName, assemblyName);

            builder.Documentation = documentation;
            builder.TagOutputHint = tagOutputHint;
            builder.CaseSensitive = caseSensitive;

            foreach (var tagMatchingRule in tagMatchingRules)
            {
                var rule = tagMatchingRule.Value <JObject>();
                builder.TagMatchingRule(b => ReadTagMatchingRule(b, rule, serializer));
            }

            foreach (var boundAttribute in boundAttributes)
            {
                var attribute = boundAttribute.Value <JObject>();
                builder.BindAttribute(b => ReadBoundAttribute(b, attribute, serializer));
            }

            foreach (var childTag in childTags)
            {
                var tag = childTag.Value <JObject>();
                builder.AllowChildTag(childTagBuilder => ReadAllowedChildTag(childTagBuilder, tag, serializer));
            }

            foreach (var diagnostic in diagnostics)
            {
                var diagnosticReader = diagnostic.CreateReader();
                var diagnosticObject = serializer.Deserialize <RazorDiagnostic>(diagnosticReader);
                builder.Diagnostics.Add(diagnosticObject);
            }

            var metadataReader = metadata.CreateReader();
            var metadataValue  = serializer.Deserialize <Dictionary <string, string> >(metadataReader);

            foreach (var item in metadataValue)
            {
                builder.Metadata[item.Key] = item.Value;
            }

            return(builder.Build());
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType != JsonToken.StartObject)
            {
                return(null);
            }

            // Required tokens (order matters)
            var descriptorKind = reader.ReadNextStringProperty(nameof(TagHelperDescriptor.Kind));
            var typeName       = reader.ReadNextStringProperty(nameof(TagHelperDescriptor.Name));
            var assemblyName   = reader.ReadNextStringProperty(nameof(TagHelperDescriptor.AssemblyName));
            var builder        = TagHelperDescriptorBuilder.Create(descriptorKind, typeName, assemblyName);

            reader.ReadProperties(propertyName =>
            {
                switch (propertyName)
                {
                case nameof(TagHelperDescriptor.Documentation):
                    if (reader.Read())
                    {
                        var documentation     = (string)reader.Value;
                        builder.Documentation = documentation;
                    }
                    break;

                case nameof(TagHelperDescriptor.TagOutputHint):
                    if (reader.Read())
                    {
                        var tagOutputHint     = (string)reader.Value;
                        builder.TagOutputHint = tagOutputHint;
                    }
                    break;

                case nameof(TagHelperDescriptor.CaseSensitive):
                    if (reader.Read())
                    {
                        var caseSensitive     = (bool)reader.Value;
                        builder.CaseSensitive = caseSensitive;
                    }
                    break;

                case nameof(TagHelperDescriptor.TagMatchingRules):
                    ReadTagMatchingRules(reader, builder);
                    break;

                case nameof(TagHelperDescriptor.BoundAttributes):
                    ReadBoundAttributes(reader, builder);
                    break;

                case nameof(TagHelperDescriptor.AllowedChildTags):
                    ReadAllowedChildTags(reader, builder);
                    break;

                case nameof(TagHelperDescriptor.Diagnostics):
                    ReadDiagnostics(reader, builder.Diagnostics);
                    break;

                case nameof(TagHelperDescriptor.Metadata):
                    ReadMetadata(reader, builder.Metadata);
                    break;
                }
            });

            return(builder.Build());
        }
        public void ViewComponentTagHelperPass_Execute_CreatesViewComponentTagHelper()
        {
            // Arrange
            var codeDocument = CreateDocument(@"
@addTagHelper TestTagHelper, TestAssembly
<tagcloud foo=""17"">");

            var tagHelpers = new[]
            {
                TagHelperDescriptorBuilder.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly")
                    .TypeName("__Generated__TagCloudViewComponentTagHelper")
                    .BoundAttributeDescriptor(attribute => attribute
                        .Name("Foo")
                        .TypeName("System.Int32")
                        .PropertyName("Foo"))
                    .TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud"))
                    .AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud")
                    .Build()
            };

            var engine = CreateEngine(tagHelpers);
            var pass = new ViewComponentTagHelperPass()
            {
                Engine = engine,
            };

            var irDocument = CreateIRDocument(engine, codeDocument);

            var vcthFullName = "AspNetCore.test_cshtml.__Generated__TagCloudViewComponentTagHelper";

            // Act
            pass.Execute(codeDocument, irDocument);

            // Assert
            var tagHelper = FindTagHelperNode(irDocument);
            Assert.Equal(vcthFullName, Assert.IsType<DefaultTagHelperCreateIntermediateNode>(tagHelper.Children[1]).TypeName);
            Assert.Equal("Foo", Assert.IsType<DefaultTagHelperPropertyIntermediateNode>(tagHelper.Children[2]).PropertyName);


            var @class = FindClassNode(irDocument);
            Assert.Equal(4, @class.Children.Count);

            var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children.Last());
            var tokenNode = vcthClass.Children[0] as IntermediateToken;
            Assert.Equal(
                @"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")]
public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
    private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
    public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)
    {
        _helper = helper;
    }
    [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]
    public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }
    public System.Int32 Foo { get; set; }
    public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)
    {
        (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
        var content = await _helper.InvokeAsync(""TagCloud"", new { Foo });
        output.TagName = null;
        output.Content.SetHtmlContent(content);
    }
}
",
                tokenNode.Content,
                ignoreLineEndingDifferences: true);
            Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
        }
Exemplo n.º 28
0
        public DefaultProjectSnapshotManagerTest()
        {
            TagHelperResolver = new TestTagHelperResolver();

            HostServices = TestServices.Create(
                new IWorkspaceService[]
            {
                new TestProjectSnapshotProjectEngineFactory(),
            },
                new ILanguageService[]
            {
                TagHelperResolver,
            });

            Documents = new HostDocument[]
            {
                new HostDocument("c:\\MyProject\\File.cshtml", "File.cshtml"),
                new HostDocument("c:\\MyProject\\Index.cshtml", "Index.cshtml"),

                // linked file
                new HostDocument("c:\\SomeOtherProject\\Index.cshtml", "Pages\\Index.cshtml"),
            };

            HostProject = new HostProject("c:\\MyProject\\Test.csproj", FallbackRazorConfiguration.MVC_2_0);
            HostProjectWithConfigurationChange = new HostProject("c:\\MyProject\\Test.csproj", FallbackRazorConfiguration.MVC_1_0);

            Workspace      = TestWorkspace.Create(HostServices);
            ProjectManager = new TestProjectSnapshotManager(Dispatcher, Enumerable.Empty <ProjectSnapshotChangeTrigger>(), Workspace);

            var projectId = ProjectId.CreateNewId("Test");
            var solution  = Workspace.CurrentSolution.AddProject(ProjectInfo.Create(
                                                                     projectId,
                                                                     VersionStamp.Default,
                                                                     "Test",
                                                                     "Test",
                                                                     LanguageNames.CSharp,
                                                                     "c:\\MyProject\\Test.csproj"));

            WorkspaceProject = solution.GetProject(projectId);

            var vbProjectId = ProjectId.CreateNewId("VB");

            solution = solution.AddProject(ProjectInfo.Create(
                                               vbProjectId,
                                               VersionStamp.Default,
                                               "VB",
                                               "VB",
                                               LanguageNames.VisualBasic,
                                               "VB.vbproj"));
            VBWorkspaceProject = solution.GetProject(vbProjectId);

            var projectWithoutFilePathId = ProjectId.CreateNewId("NoFile");

            solution = solution.AddProject(ProjectInfo.Create(
                                               projectWithoutFilePathId,
                                               VersionStamp.Default,
                                               "NoFile",
                                               "NoFile",
                                               LanguageNames.CSharp));
            WorkspaceProjectWithoutFilePath = solution.GetProject(projectWithoutFilePathId);

            // Approximates a project with multi-targeting
            var projectIdWithDifferentTfm = ProjectId.CreateNewId("TestWithDifferentTfm");

            solution = Workspace.CurrentSolution.AddProject(ProjectInfo.Create(
                                                                projectIdWithDifferentTfm,
                                                                VersionStamp.Default,
                                                                "Test (Different TFM)",
                                                                "Test",
                                                                LanguageNames.CSharp,
                                                                "c:\\MyProject\\Test.csproj"));
            WorkspaceProjectWithDifferentTfm = solution.GetProject(projectIdWithDifferentTfm);

            SomeTagHelpers = TagHelperResolver.TagHelpers;
            SomeTagHelpers.Add(TagHelperDescriptorBuilder.Create("Test1", "TestAssembly").Build());

            SourceText = SourceText.From("Hello world");
        }
        private List <TagHelperDescriptor> CreateEventHandlerTagHelpers(List <EventHandlerData> data)
        {
            var results = new List <TagHelperDescriptor>();

            for (var i = 0; i < data.Count; i++)
            {
                var entry         = data[i];
                var attributeName = "@" + entry.Attribute;
                var eventArgType  = entry.EventArgsType.ToDisplayString();

                var builder = TagHelperDescriptorBuilder.Create(ComponentMetadata.EventHandler.TagHelperKind, entry.Attribute, ComponentsApi.AssemblyName);
                builder.CaseSensitive = true;
                builder.Documentation = string.Format(
                    CultureInfo.CurrentCulture,
                    ComponentResources.EventHandlerTagHelper_Documentation,
                    attributeName,
                    eventArgType);

                builder.Metadata.Add(ComponentMetadata.SpecialKindKey, ComponentMetadata.EventHandler.TagHelperKind);
                builder.Metadata.Add(ComponentMetadata.EventHandler.EventArgsType, eventArgType);
                builder.Metadata.Add(TagHelperMetadata.Common.ClassifyAttributesOnly, bool.TrueString);
                builder.Metadata[TagHelperMetadata.Runtime.Name] = ComponentMetadata.EventHandler.RuntimeName;

                // WTE has a bug in 15.7p1 where a Tag Helper without a display-name that looks like
                // a C# property will crash trying to create the tooltips.
                builder.SetTypeName(entry.TypeName);

                builder.TagMatchingRule(rule =>
                {
                    rule.TagName = "*";

                    rule.Attribute(a =>
                    {
                        a.Name = attributeName;
                        a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                        a.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                    });
                });

                if (entry.EnablePreventDefault)
                {
                    builder.TagMatchingRule(rule =>
                    {
                        rule.TagName = "*";

                        rule.Attribute(a =>
                        {
                            a.Name = attributeName + ":preventDefault";
                            a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                            a.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                        });
                    });
                }

                if (entry.EnableStopPropagation)
                {
                    builder.TagMatchingRule(rule =>
                    {
                        rule.TagName = "*";

                        rule.Attribute(a =>
                        {
                            a.Name = attributeName + ":stopPropagation";
                            a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                            a.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;
                        });
                    });
                }

                builder.BindAttribute(a =>
                {
                    a.Documentation = string.Format(
                        CultureInfo.CurrentCulture,
                        ComponentResources.EventHandlerTagHelper_Documentation,
                        attributeName,
                        eventArgType);

                    a.Name = attributeName;

                    // We want event handler directive attributes to default to C# context.
                    a.TypeName = $"Microsoft.AspNetCore.Components.EventCallback<{eventArgType}>";

                    // But make this weakly typed (don't type check) - delegates have their own type-checking
                    // logic that we don't want to interfere with.
                    a.Metadata.Add(ComponentMetadata.Component.WeaklyTypedKey, bool.TrueString);

                    a.Metadata[ComponentMetadata.Common.DirectiveAttribute] = bool.TrueString;

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the tooltips.
                    a.SetPropertyName(entry.Attribute);

                    if (entry.EnablePreventDefault)
                    {
                        a.BindAttributeParameter(parameter =>
                        {
                            parameter.Name          = "preventDefault";
                            parameter.TypeName      = typeof(bool).FullName;
                            parameter.Documentation = string.Format(
                                CultureInfo.CurrentCulture, ComponentResources.EventHandlerTagHelper_PreventDefault_Documentation, attributeName);

                            parameter.SetPropertyName("PreventDefault");
                        });
                    }

                    if (entry.EnableStopPropagation)
                    {
                        a.BindAttributeParameter(parameter =>
                        {
                            parameter.Name          = "stopPropagation";
                            parameter.TypeName      = typeof(bool).FullName;
                            parameter.Documentation = string.Format(
                                CultureInfo.CurrentCulture, ComponentResources.EventHandlerTagHelper_StopPropagation_Documentation, attributeName);

                            parameter.SetPropertyName("StopPropagation");
                        });
                    }
                });

                results.Add(builder.Build());
            }

            return(results);
        }
Exemplo n.º 30
0
        private List <TagHelperDescriptor> CreateElementBindTagHelpers(List <ElementBindData> data)
        {
            var results = new List <TagHelperDescriptor>();

            for (var i = 0; i < data.Count; i++)
            {
                var entry = data[i];

                var name          = entry.Suffix == null ? "Bind" : "Bind_" + entry.Suffix;
                var attributeName = entry.Suffix == null ? "bind" : "bind-" + entry.Suffix;

                var formatName          = entry.Suffix == null ? "Format_" + entry.ValueAttribute : "Format_" + entry.Suffix;
                var formatAttributeName = entry.Suffix == null ? "format-" + entry.ValueAttribute : "format-" + entry.Suffix;

                var builder = TagHelperDescriptorBuilder.Create(BlazorMetadata.Bind.TagHelperKind, name, entry.Assembly);
                builder.Documentation = string.Format(
                    Resources.BindTagHelper_Element_Documentation,
                    entry.ValueAttribute,
                    entry.ChangeAttribute);

                builder.Metadata.Add(BlazorMetadata.SpecialKindKey, BlazorMetadata.Bind.TagHelperKind);
                builder.Metadata[TagHelperMetadata.Runtime.Name]      = BlazorMetadata.Bind.RuntimeName;
                builder.Metadata[BlazorMetadata.Bind.ValueAttribute]  = entry.ValueAttribute;
                builder.Metadata[BlazorMetadata.Bind.ChangeAttribute] = entry.ChangeAttribute;

                if (entry.TypeAttribute != null)
                {
                    // For entries that map to the <input /> element, we need to be able to know
                    // the difference between <input /> and <input type="text" .../> for which we
                    // want to use the same attributes.
                    //
                    // We provide a tag helper for <input /> that should match all input elements,
                    // but we only want it to be used when a more specific one is used.
                    //
                    // Therefore we use this metadata to know which one is more specific when two
                    // tag helpers match.
                    builder.Metadata[BlazorMetadata.Bind.TypeAttribute] = entry.TypeAttribute;
                }

                // WTE has a bug in 15.7p1 where a Tag Helper without a display-name that looks like
                // a C# property will crash trying to create the toolips.
                builder.SetTypeName(entry.TypeName);

                builder.TagMatchingRule(rule =>
                {
                    rule.TagName = entry.Element;
                    if (entry.TypeAttribute != null)
                    {
                        rule.Attribute(a =>
                        {
                            a.Name = "type";
                            a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                            a.Value = entry.TypeAttribute;
                            a.ValueComparisonMode = RequiredAttributeDescriptor.ValueComparisonMode.FullMatch;
                        });
                    }

                    rule.Attribute(a =>
                    {
                        a.Name = attributeName;
                        a.NameComparisonMode = RequiredAttributeDescriptor.NameComparisonMode.FullMatch;
                    });
                });

                builder.BindAttribute(a =>
                {
                    a.Documentation = string.Format(
                        Resources.BindTagHelper_Element_Documentation,
                        entry.ValueAttribute,
                        entry.ChangeAttribute);

                    a.Name     = attributeName;
                    a.TypeName = typeof(object).FullName;

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the toolips.
                    a.SetPropertyName(name);
                });

                builder.BindAttribute(attribute =>
                {
                    attribute.Documentation = string.Format(Resources.BindTagHelper_Element_Format_Documentation, attributeName);

                    attribute.Name     = formatAttributeName;
                    attribute.TypeName = "System.String";

                    // WTE has a bug 15.7p1 where a Tag Helper without a display-name that looks like
                    // a C# property will crash trying to create the toolips.
                    attribute.SetPropertyName(formatName);
                });

                results.Add(builder.Build());
            }

            return(results);
        }