public void GetElementCompletions_AllowedChildrenAreIgnoredWhenAtRoot() { // Arrange var documentDescriptors = new[] { TagHelperDescriptorBuilder.Create("CatchAll", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") .Build(), }; var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >()); var existingCompletions = Enumerable.Empty <string>(); var completionContext = BuildElementCompletionContext( documentDescriptors, existingCompletions, containingTagName: null, containingParentTagName: null); var service = CreateTagHelperCompletionFactsService(); // Act var completions = service.GetElementCompletions(completionContext); // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); }
public void GetElementCompletions_CapturesAllAllowedChildTagsFromParentTagHelpers_SomeTagHelpers() { // Arrange var documentDescriptors = new[] { TagHelperDescriptorBuilder.Create("BoldParent", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .AllowChildTag("b") .AllowChildTag("bold") .AllowChildTag("div") .Build(), }; var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >() { ["b"] = new HashSet <TagHelperDescriptor>(), ["bold"] = new HashSet <TagHelperDescriptor>(), ["div"] = new HashSet <TagHelperDescriptor> { documentDescriptors[0] } }); var completionContext = BuildElementCompletionContext(documentDescriptors, Enumerable.Empty <string>(), containingTagName: "div"); var service = CreateTagHelperCompletionFactsService(); // Act var completions = service.GetElementCompletions(completionContext); // Assert AssertCompletionsAreEquivalent(expectedCompletions, completions); }
public void GetElementCompletions_EnsuresDescriptorsHaveSatisfiedParent() { // Arrange var documentDescriptors = new[] { TagHelperDescriptorBuilder.Create("LiTagHelper1", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) .Build(), TagHelperDescriptorBuilder.Create("LiTagHelper2", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li").RequireParentTag("ol")) .Build(), }; var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >() { ["li"] = 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_OutputHintIsCrossReferencedWithExistingCompletions() { // Arrange var documentDescriptors = new[] { TagHelperDescriptorBuilder.Create("DivTagHelper", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("div")) .TagOutputHint("li") .Build(), TagHelperDescriptorBuilder.Create("LiTagHelper", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("li")) .TagOutputHint("strong") .Build(), }; var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >() { ["div"] = new HashSet <TagHelperDescriptor> { documentDescriptors[0] }, ["li"] = new HashSet <TagHelperDescriptor> { documentDescriptors[1] }, }); 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_CatchAllsApplyToOnlyTagHelperCompletions() { // Arrange var documentDescriptors = new[] { TagHelperDescriptorBuilder.Create("SuperLiTagHelper", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("superli")) .Build(), TagHelperDescriptorBuilder.Create("CatchAll", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("*")) .Build(), }; var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >() { ["superli"] = new HashSet <TagHelperDescriptor>() { documentDescriptors[0], documentDescriptors[1] }, ["li"] = new HashSet <TagHelperDescriptor>(), }); 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_AllowsMultiTargetingTagHelpers() { // Arrange var documentDescriptors = new[] { TagHelperDescriptorBuilder.Create("BoldTagHelper1", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("b")) .TagMatchingRuleDescriptor(rule => rule.RequireTagName("bold")) .Build(), TagHelperDescriptorBuilder.Create("BoldTagHelper2", "TestAssembly") .TagMatchingRuleDescriptor(rule => rule.RequireTagName("strong")) .Build(), }; var expectedCompletions = ElementCompletionResult.Create(new Dictionary <string, HashSet <TagHelperDescriptor> >() { ["strong"] = new HashSet <TagHelperDescriptor> { documentDescriptors[0], documentDescriptors[1] }, ["b"] = new HashSet <TagHelperDescriptor> { documentDescriptors[0] }, ["bold"] = new HashSet <TagHelperDescriptor> { documentDescriptors[0] }, }); var existingCompletions = new[] { "strong", "b", "bold" }; 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 override ElementCompletionResult GetElementCompletions(ElementCompletionContext completionContext) { if (completionContext == null) { throw new ArgumentNullException(nameof(completionContext)); } var elementCompletions = new Dictionary <string, HashSet <TagHelperDescriptor> >(StringComparer.OrdinalIgnoreCase); AddAllowedChildrenCompletions(completionContext, elementCompletions); if (elementCompletions.Count > 0) { // If the containing element is already a TagHelper and only allows certain children. var emptyResult = ElementCompletionResult.Create(elementCompletions); return(emptyResult); } elementCompletions = completionContext.ExistingCompletions.ToDictionary( completion => completion, _ => new HashSet <TagHelperDescriptor>(), StringComparer.OrdinalIgnoreCase); var catchAllDescriptors = new HashSet <TagHelperDescriptor>(); var prefix = completionContext.DocumentContext.Prefix ?? string.Empty; var possibleChildDescriptors = _tagHelperFactsService.GetTagHelpersGivenParent(completionContext.DocumentContext, completionContext.ContainingTagName); foreach (var possibleDescriptor in possibleChildDescriptors) { var addRuleCompletions = false; var outputHint = possibleDescriptor.TagOutputHint; foreach (var rule in possibleDescriptor.TagMatchingRules) { if (rule.TagName == TagHelperMatchingConventions.ElementCatchAllName) { catchAllDescriptors.Add(possibleDescriptor); } else if (elementCompletions.ContainsKey(rule.TagName)) { addRuleCompletions = true; } else if (outputHint != null) { // If the current descriptor has an output hint we need to make sure it shows up only when its output hint would normally show up. // Example: We have a MyTableTagHelper that has an output hint of "table" and a MyTrTagHelper that has an output hint of "tr". // If we try typing in a situation like this: <body > | </body> // We'd expect to only get "my-table" as a completion because the "body" tag doesn't allow "tr" tags. addRuleCompletions = elementCompletions.ContainsKey(outputHint); } else if (!completionContext.InHTMLSchema(rule.TagName)) { // If there is an unknown HTML schema tag that doesn't exist in the current completion we should add it. This happens for // TagHelpers that target non-schema oriented tags. addRuleCompletions = true; } if (addRuleCompletions) { UpdateCompletions(prefix + rule.TagName, possibleDescriptor); } } } // We needed to track all catch-alls and update their completions after all other completions have been completed. // This way, any TagHelper added completions will also have catch-alls listed under their entries. foreach (var catchAllDescriptor in catchAllDescriptors) { foreach (var completionTagName in elementCompletions.Keys) { if (elementCompletions[completionTagName].Count > 0 || !string.IsNullOrEmpty(prefix) && completionTagName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { // The current completion either has other TagHelper's associated with it or is prefixed with a non-empty // TagHelper prefix. UpdateCompletions(completionTagName, catchAllDescriptor); } } } var result = ElementCompletionResult.Create(elementCompletions); return(result); void UpdateCompletions(string tagName, TagHelperDescriptor possibleDescriptor) { if (!elementCompletions.TryGetValue(tagName, out var existingRuleDescriptors)) { existingRuleDescriptors = new HashSet <TagHelperDescriptor>(); elementCompletions[tagName] = existingRuleDescriptors; } existingRuleDescriptors.Add(possibleDescriptor); } }