public void GetDescriptors_LocatesNestedRemoveTagHelperChunkGenerator()
        {
            // Arrange
            var resolver = new TestTagHelperDescriptorResolver();
            var tagHelperDirectiveSpanVisitor = new TagHelperDirectiveSpanVisitor(resolver, new ErrorSink());
            var document = new MarkupBlock(
                new DirectiveBlock(
                    Factory.CodeTransition(),
                    Factory.MetaCode(SyntaxConstants.CSharp.RemoveTagHelperKeyword + " ")
                    .Accepts(AcceptedCharacters.None),
                    Factory.Code("\"something\"").AsRemoveTagHelper("something"))
                );
            var expectedRegistration = new TagHelperDirectiveDescriptor
            {
                DirectiveText = "something",
                DirectiveType = TagHelperDirectiveType.RemoveTagHelper
            };

            // Act
            tagHelperDirectiveSpanVisitor.GetDescriptors(document);

            // Assert
            var directiveDescriptor = Assert.Single(resolver.DirectiveDescriptors);

            Assert.Equal(expectedRegistration, directiveDescriptor, TagHelperDirectiveDescriptorComparer.Default);
        }
        public override void VisitSpan(Span span)
        {
            // We're only interested in spans with an AddOrRemoveTagHelperChunkGenerator.

            if (span.ChunkGenerator is AddOrRemoveTagHelperChunkGenerator)
            {
                var chunkGenerator = (AddOrRemoveTagHelperChunkGenerator)span.ChunkGenerator;

                var directive =
                    chunkGenerator.RemoveTagHelperDescriptors ?
                    TagHelperDirectiveType.RemoveTagHelper :
                    TagHelperDirectiveType.AddTagHelper;

                var directiveDescriptor = new TagHelperDirectiveDescriptor(
                    chunkGenerator.LookupText,
                    span.Start,
                    directive);

                _directiveDescriptors.Add(directiveDescriptor);
            }
            else if (span.ChunkGenerator is TagHelperPrefixDirectiveChunkGenerator)
            {
                var chunkGenerator = (TagHelperPrefixDirectiveChunkGenerator)span.ChunkGenerator;

                var directiveDescriptor = new TagHelperDirectiveDescriptor(
                    chunkGenerator.Prefix,
                    span.Start,
                    TagHelperDirectiveType.TagHelperPrefix);

                _directiveDescriptors.Add(directiveDescriptor);
            }
        }
Example #3
0
        public void GetDescriptors_LocatesTagHelperCodeGenerator_CreatesDirectiveDescriptors()
        {
            // Arrange
            var resolver = new TestTagHelperDescriptorResolver();
            var tagHelperDirectiveSpanVisitor = new TagHelperDirectiveSpanVisitor(resolver, new ParserErrorSink());
            var document = new MarkupBlock(
                Factory.Code("\"one\"").AsAddTagHelper("one"),
                Factory.Code("\"two\"").AsRemoveTagHelper("two"),
                Factory.Code("\"three\"").AsRemoveTagHelper("three"),
                Factory.Code("\"four\"").AsTagHelperPrefixDirective("four"));
            var expectedDescriptors = new TagHelperDirectiveDescriptor[]
            {
                new TagHelperDirectiveDescriptor("one", TagHelperDirectiveType.AddTagHelper),
                new TagHelperDirectiveDescriptor("two", TagHelperDirectiveType.RemoveTagHelper),
                new TagHelperDirectiveDescriptor("three", TagHelperDirectiveType.RemoveTagHelper),
                new TagHelperDirectiveDescriptor("four", TagHelperDirectiveType.TagHelperPrefix),
            };

            // Act
            tagHelperDirectiveSpanVisitor.GetDescriptors(document);

            // Assert
            Assert.Equal(
                expectedDescriptors,
                resolver.DirectiveDescriptors,
                TagHelperDirectiveDescriptorComparer.Default);
        }
Example #4
0
        public void GetDescriptors_LocatesTagHelperPrefixDirectiveCodeGenerator()
        {
            // Arrange
            var resolver = new TestTagHelperDescriptorResolver();
            var tagHelperDirectiveSpanVisitor = new TagHelperDirectiveSpanVisitor(resolver, new ParserErrorSink());
            var document = new MarkupBlock(
                new DirectiveBlock(
                    Factory.CodeTransition(),
                    Factory
                    .MetaCode(SyntaxConstants.CSharp.TagHelperPrefixKeyword + " ")
                    .Accepts(AcceptedCharacters.None),
                    Factory.Code("\"something\"").AsTagHelperPrefixDirective("something")));
            var expectedDirectiveDescriptor =
                new TagHelperDirectiveDescriptor("something", TagHelperDirectiveType.TagHelperPrefix);

            // Act
            tagHelperDirectiveSpanVisitor.GetDescriptors(document);

            // Assert
            var directiveDescriptor = Assert.Single(resolver.DirectiveDescriptors);

            Assert.Equal(
                expectedDirectiveDescriptor,
                directiveDescriptor,
                TagHelperDirectiveDescriptorComparer.Default);
        }
Example #5
0
        private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDescriptors(
           IReadOnlyList<CodeTree> inheritedCodeTrees,
           IReadOnlyList<Chunk> defaultInheritedChunks)
        {
            var descriptors = new List<TagHelperDirectiveDescriptor>();

            // For tag helpers, the @removeTagHelper only applies tag helpers that were added prior to it.
            // Consequently we must visit tag helpers outside-in - furthest _GlobalImport first and nearest one last.
            // This is different from the behavior of chunk merging where we visit the nearest one first and ignore
            // chunks that were previously visited.
            var chunksFromGlobalImports = inheritedCodeTrees
                .Reverse()
                .SelectMany(tree => tree.Chunks);
            var chunksInOrder = defaultInheritedChunks.Concat(chunksFromGlobalImports);
            foreach (var chunk in chunksInOrder)
            {
                // All TagHelperDirectiveDescriptors created here have undefined source locations because the source 
                // that created them is not in the same file.
                var addTagHelperChunk = chunk as AddTagHelperChunk;
                if (addTagHelperChunk != null)
                {
                    var descriptor = new TagHelperDirectiveDescriptor(
                        addTagHelperChunk.LookupText,
                        SourceLocation.Undefined,
                        TagHelperDirectiveType.AddTagHelper);

                    descriptors.Add(descriptor);

                    continue;
                }

                var removeTagHelperChunk = chunk as RemoveTagHelperChunk;
                if (removeTagHelperChunk != null)
                {
                    var descriptor = new TagHelperDirectiveDescriptor(
                        removeTagHelperChunk.LookupText,
                        SourceLocation.Undefined,
                        TagHelperDirectiveType.RemoveTagHelper);

                    descriptors.Add(descriptor);

                    continue;
                }

                var tagHelperPrefixDirectiveChunk = chunk as TagHelperPrefixDirectiveChunk;
                if (tagHelperPrefixDirectiveChunk != null)
                {
                    var descriptor = new TagHelperDirectiveDescriptor(
                        tagHelperPrefixDirectiveChunk.Prefix,
                        SourceLocation.Undefined,
                        TagHelperDirectiveType.TagHelperPrefix);

                    descriptors.Add(descriptor);
                }
            }

            return descriptors;
        }
Example #6
0
        public void GetDescriptors_CanOverrideResolutionContext()
        {
            // Arrange
            var resolver = new TestTagHelperDescriptorResolver();
            var expectedInitialDirectiveDescriptors = new TagHelperDirectiveDescriptor[]
            {
                new TagHelperDirectiveDescriptor("one", TagHelperDirectiveType.AddTagHelper),
                new TagHelperDirectiveDescriptor("two", TagHelperDirectiveType.RemoveTagHelper),
                new TagHelperDirectiveDescriptor("three", TagHelperDirectiveType.RemoveTagHelper),
                new TagHelperDirectiveDescriptor("four", TagHelperDirectiveType.TagHelperPrefix),
            };
            var expectedEndDirectiveDescriptors = new TagHelperDirectiveDescriptor[]
            {
                new TagHelperDirectiveDescriptor("custom", TagHelperDirectiveType.AddTagHelper)
            };
            var tagHelperDirectiveSpanVisitor = new CustomTagHelperDirectiveSpanVisitor(
                resolver,
                (descriptors, errorSink) =>
            {
                Assert.Equal(
                    expectedInitialDirectiveDescriptors,
                    descriptors,
                    TagHelperDirectiveDescriptorComparer.Default);

                return(new TagHelperDescriptorResolutionContext(expectedEndDirectiveDescriptors, errorSink));
            });
            var document = new MarkupBlock(
                Factory.Code("\"one\"").AsAddTagHelper("one"),
                Factory.Code("\"two\"").AsRemoveTagHelper("two"),
                Factory.Code("\"three\"").AsRemoveTagHelper("three"),
                Factory.Code("\"four\"").AsTagHelperPrefixDirective("four"));


            // Act
            tagHelperDirectiveSpanVisitor.GetDescriptors(document);

            // Assert
            Assert.Equal(expectedEndDirectiveDescriptors,
                         resolver.DirectiveDescriptors,
                         TagHelperDirectiveDescriptorComparer.Default);
        }
Example #7
0
        public void GetTagHelperDescriptors_ReturnsExpectedDirectiveDescriptors(
            CodeTree[] codeTrees,
            TagHelperDirectiveDescriptor[] expectedDirectiveDescriptors)
        {
            // Arrange
            var builder = new BlockBuilder { Type = BlockType.Comment };
            var block = new Block(builder);

            IList<TagHelperDirectiveDescriptor> descriptors = null;
            var resolver = new Mock<ITagHelperDescriptorResolver>();
            resolver.Setup(r => r.Resolve(It.IsAny<TagHelperDescriptorResolutionContext>()))
                    .Callback((TagHelperDescriptorResolutionContext context) =>
                    {
                        descriptors = context.DirectiveDescriptors;
                    })
                    .Returns(Enumerable.Empty<TagHelperDescriptor>())
                    .Verifiable();

            var baseParser = new RazorParser(
                new CSharpCodeParser(),
                new HtmlMarkupParser(),
                tagHelperDescriptorResolver: resolver.Object);
            var parser = new TestableMvcRazorParser(baseParser, codeTrees, defaultInheritedChunks: new Chunk[0]);

            // Act
            parser.GetTagHelperDescriptorsPublic(block, errorSink: new ErrorSink()).ToArray();

            // Assert
            Assert.NotNull(descriptors);
            Assert.Equal(expectedDirectiveDescriptors.Length, descriptors.Count);

            for (var i = 0; i < expectedDirectiveDescriptors.Length; i++)
            {
                var expected = expectedDirectiveDescriptors[i];
                var actual = descriptors[i];

                Assert.Equal(expected.DirectiveText, actual.DirectiveText, StringComparer.Ordinal);
                Assert.Equal(SourceLocation.Zero, actual.Location);
                Assert.Equal(expected.DirectiveType, actual.DirectiveType);
            }
        }
        public override void VisitSpan(Span span)
        {
            // We're only interested in spans with an AddOrRemoveTagHelperChunkGenerator.

            if (span.ChunkGenerator is AddOrRemoveTagHelperChunkGenerator)
            {
                var chunkGenerator = (AddOrRemoveTagHelperChunkGenerator)span.ChunkGenerator;

                var directive =
                    chunkGenerator.RemoveTagHelperDescriptors ?
                    TagHelperDirectiveType.RemoveTagHelper :
                    TagHelperDirectiveType.AddTagHelper;
                var textLocation = GetSubTextSourceLocation(span, chunkGenerator.LookupText);

                var directiveDescriptor = new TagHelperDirectiveDescriptor
                {
                    DirectiveText = chunkGenerator.LookupText,
                    Location = textLocation,
                    DirectiveType = directive
                };

                _directiveDescriptors.Add(directiveDescriptor);
            }
            else if (span.ChunkGenerator is TagHelperPrefixDirectiveChunkGenerator)
            {
                var chunkGenerator = (TagHelperPrefixDirectiveChunkGenerator)span.ChunkGenerator;
                var textLocation = GetSubTextSourceLocation(span, chunkGenerator.Prefix);

                var directiveDescriptor = new TagHelperDirectiveDescriptor
                {
                    DirectiveText = chunkGenerator.Prefix,
                    Location = textLocation,
                    DirectiveType = TagHelperDirectiveType.TagHelperPrefix
                };

                _directiveDescriptors.Add(directiveDescriptor);
            }
        }
        private static LookupInfo GetLookupInfo(TagHelperDirectiveDescriptor directiveDescriptor,
                                                ErrorSink errorSink)
        {
            var lookupText = directiveDescriptor.DirectiveText;
            var lookupStrings = lookupText?.Split(new[] { ',' });

            // Ensure that we have valid lookupStrings to work with. Valid formats are:
            // "assemblyName"
            // "typeName, assemblyName"
            if (lookupStrings == null ||
                lookupStrings.Any(string.IsNullOrWhiteSpace) ||
                lookupStrings.Length != 2)
            {
                errorSink.OnError(
                    directiveDescriptor.Location,
                    Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText));

                return null;
            }

            return new LookupInfo
            {
                TypePattern = lookupStrings[0].Trim(),
                AssemblyName = lookupStrings[1].Trim()
            };
        }
        private static LookupInfo GetLookupInfo(
            TagHelperDirectiveDescriptor directiveDescriptor,
            ErrorSink errorSink)
        {
            var lookupText = directiveDescriptor.DirectiveText;
            var lookupStrings = lookupText?.Split(new[] { ',' });

            // Ensure that we have valid lookupStrings to work with. The valid format is "typeName, assemblyName"
            if (lookupStrings == null ||
                lookupStrings.Any(string.IsNullOrWhiteSpace) ||
                lookupStrings.Length != 2)
            {
                errorSink.OnError(
                    directiveDescriptor.Location,
                    Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText),
                    GetErrorLength(lookupText));

                return null;
            }

            var trimmedAssemblyName = lookupStrings[1].Trim();

            // + 1 is for the comma separator in the lookup text.
            var assemblyNameIndex = lookupStrings[0].Length + 1 + lookupStrings[1].IndexOf(trimmedAssemblyName);
            var assemblyNamePrefix = directiveDescriptor.DirectiveText.Substring(0, assemblyNameIndex);
            var assemblyNameLocation = SourceLocation.Advance(directiveDescriptor.Location, assemblyNamePrefix);

            return new LookupInfo
            {
                TypePattern = lookupStrings[0].Trim(),
                AssemblyName = trimmedAssemblyName,
                AssemblyNameLocation = assemblyNameLocation,
            };
        }
Example #11
0
        private static IEnumerable<TagHelperDirectiveDescriptor> GetTagHelperDirectiveDescriptors(
           IReadOnlyList<ChunkTree> inheritedChunkTrees,
           IReadOnlyList<Chunk> defaultInheritedChunks)
        {
            var descriptors = new List<TagHelperDirectiveDescriptor>();

            var inheritedChunks = defaultInheritedChunks.Concat(inheritedChunkTrees.SelectMany(tree => tree.Chunks));
            foreach (var chunk in inheritedChunks)
            {
                // All TagHelperDirectiveDescriptors created here have undefined source locations because the source
                // that created them is not in the same file.
                var addTagHelperChunk = chunk as AddTagHelperChunk;
                if (addTagHelperChunk != null)
                {
                    var descriptor = new TagHelperDirectiveDescriptor
                    {
                        DirectiveText = addTagHelperChunk.LookupText,
                        Location = chunk.Start,
                        DirectiveType = TagHelperDirectiveType.AddTagHelper
                    };

                    descriptors.Add(descriptor);

                    continue;
                }

                var removeTagHelperChunk = chunk as RemoveTagHelperChunk;
                if (removeTagHelperChunk != null)
                {
                    var descriptor = new TagHelperDirectiveDescriptor
                    {
                        DirectiveText = removeTagHelperChunk.LookupText,
                        Location = chunk.Start,
                        DirectiveType = TagHelperDirectiveType.RemoveTagHelper
                    };

                    descriptors.Add(descriptor);

                    continue;
                }

                var tagHelperPrefixDirectiveChunk = chunk as TagHelperPrefixDirectiveChunk;
                if (tagHelperPrefixDirectiveChunk != null)
                {
                    var descriptor = new TagHelperDirectiveDescriptor
                    {
                        DirectiveText = tagHelperPrefixDirectiveChunk.Prefix,
                        Location = chunk.Start,
                        DirectiveType = TagHelperDirectiveType.TagHelperPrefix
                    };

                    descriptors.Add(descriptor);
                }
            }

            return descriptors;
        }