protected override void Visit(TagHelperChunk chunk)
        {
            // We only want to setup tag helper manager fields if there are tag helpers, and only once
            if (!_foundTagHelpers)
            {
                _foundTagHelpers = true;

                // We want to hide declared TagHelper fields so they cannot be stepped over via a debugger.
                Writer.WriteLineHiddenDirective();

                // Runtime fields aren't useful during design time.
                if (!Context.Host.DesignTimeMode)
                {
                    // Need to disable the warning "X is assigned to but never used." for the value buffer since
                    // whether it's used depends on how a TagHelper is used.
                    Writer.WritePragma("warning disable 0414");
                    WritePrivateField(
                        _tagHelperContext.TagHelperContentTypeName,
                        CSharpTagHelperCodeRenderer.StringValueBufferVariableName,
                        value: null);
                    Writer.WritePragma("warning restore 0414");

                    WritePrivateField(
                        _tagHelperContext.ExecutionContextTypeName,
                        CSharpTagHelperCodeRenderer.ExecutionContextVariableName,
                        value: null);

                    WritePrivateField(
                        _tagHelperContext.RunnerTypeName,
                        CSharpTagHelperCodeRenderer.RunnerVariableName,
                        value: null);

                    WritePrivateField(
                        _tagHelperContext.ScopeManagerTypeName,
                        CSharpTagHelperCodeRenderer.ScopeManagerVariableName,
                        value: null);
                }
            }

            foreach (var descriptor in chunk.Descriptors)
            {
                if (!_declaredTagHelpers.Contains(descriptor.TypeName))
                {
                    _declaredTagHelpers.Add(descriptor.TypeName);

                    WritePrivateField(
                        descriptor.TypeName,
                        CSharpTagHelperCodeRenderer.GetVariableName(descriptor),
                        value: null);
                }
            }

            if (!Context.Host.DesignTimeMode)
            {
                PreAllocateUnboundTagHelperAttributes(chunk);
            }

            // We need to dive deeper to ensure we pick up any nested tag helpers.
            Accept(chunk.Children);
        }
        /// <summary>
        /// Renders the code for the given <paramref name="chunk"/>.
        /// </summary>
        /// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
        public void RenderTagHelper(TagHelperChunk chunk)
        {
            // Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when
            // multiple TargetElement attributes are on a TagHelper type and matchs overlap for an HTML element.
            // Having more than one descriptor with the same TagHelper type results in generated code that runs
            // the same TagHelper X many times (instead of once) over a single HTML element.
            var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeNameTagHelperDescriptorComparer.Default);

            RenderBeginTagHelperScope(chunk.TagName, chunk.SelfClosing, chunk.Children);

            RenderTagHelpersCreation(chunk, tagHelperDescriptors);

            var attributeDescriptors  = tagHelperDescriptors.SelectMany(descriptor => descriptor.Attributes);
            var boundHTMLAttributes   = attributeDescriptors.Select(descriptor => descriptor.Name);
            var htmlAttributes        = chunk.Attributes;
            var unboundHTMLAttributes =
                htmlAttributes.Where(htmlAttribute => !boundHTMLAttributes.Contains(htmlAttribute.Key,
                                                                                    StringComparer.OrdinalIgnoreCase));

            RenderUnboundHTMLAttributes(unboundHTMLAttributes);

            // No need to run anything in design time mode.
            if (!_designTimeMode)
            {
                RenderRunTagHelpers();
                RenderWriteTagHelperMethodCall();
                RenderEndTagHelpersScope();
            }
        }
Пример #3
0
        /// <summary>
        /// Renders the code for the given <paramref name="chunk"/>.
        /// </summary>
        /// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
        public void RenderTagHelper(TagHelperChunk chunk)
        {
            var tagHelperDescriptors = chunk.Descriptors;

            RenderBeginTagHelperScope(chunk.TagName, chunk.Children);

            RenderTagHelpersCreation(chunk);

            var attributeDescriptors  = tagHelperDescriptors.SelectMany(descriptor => descriptor.Attributes);
            var boundHTMLAttributes   = attributeDescriptors.Select(descriptor => descriptor.Name);
            var htmlAttributes        = chunk.Attributes;
            var unboundHTMLAttributes =
                htmlAttributes.Where(htmlAttribute => !boundHTMLAttributes.Contains(htmlAttribute.Key,
                                                                                    StringComparer.OrdinalIgnoreCase));

            RenderUnboundHTMLAttributes(unboundHTMLAttributes);

            RenderRunTagHelpers();

            RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
            RenderTagOutput(_tagHelperContext.OutputGeneratePreContentMethodName);

            RenderTagHelperContent();

            RenderTagOutput(_tagHelperContext.OutputGeneratePostContentMethodName);
            RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);

            RenderEndTagHelpersScope();
        }
Пример #4
0
        private void RenderTagHelpersCreation(TagHelperChunk chunk)
        {
            var tagHelperDescriptors = chunk.Descriptors;

            // This is to maintain value accessors for attributes when creating the TagHelpers.
            // Ultimately it enables us to do scenarios like this:
            // myTagHelper1.Foo = DateTime.Now;
            // myTagHelper2.Foo = myTagHelper1.Foo;
            var htmlAttributeValues = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            foreach (var tagHelperDescriptor in tagHelperDescriptors)
            {
                var tagHelperVariableName = GetVariableName(tagHelperDescriptor);

                // Create the tag helper
                _writer.WriteStartAssignment(tagHelperVariableName)
                .WriteStartMethodInvocation(_tagHelperContext.CreateTagHelperMethodName,
                                            tagHelperDescriptor.TypeName)
                .WriteEndMethodInvocation();

                // Execution contexts are a runtime feature.
                if (!_designTimeMode)
                {
                    _writer.WriteInstanceMethodInvocation(ExecutionContextVariableName,
                                                          _tagHelperContext.ExecutionContextAddMethodName,
                                                          tagHelperVariableName);
                }

                // Render all of the bound attribute values for the tag helper.
                RenderBoundHTMLAttributes(chunk.Attributes,
                                          tagHelperVariableName,
                                          tagHelperDescriptor.Attributes,
                                          htmlAttributeValues);
            }
        }
 protected override void Visit(TagHelperChunk chunk)
 {
     if (chunk.TagName == "a")
     {
         Writer.Write(@"WriteLiteral("" "");");
         TagHelperRenderer.RenderTagHelper(chunk);
         _comingOffHyperlink = true;
     }
     else
     {
         TagHelperRenderer.RenderTagHelper(chunk);
     }
 }
Пример #6
0
        protected override void Visit(TagHelperChunk chunk)
        {
            if (!_foundTagHelpers)
            {
                _foundTagHelpers = true;

                if (!ImportedUsings.Contains(TagHelpersRuntimeNamespace))
                {
                    // If we find TagHelpers then we need to add the TagHelper runtime namespace to our list of usings.
                    Writer.WriteUsing(TagHelpersRuntimeNamespace);
                    ImportedUsings.Add(TagHelpersRuntimeNamespace);
                }
            }
        }
        /// <summary>
        /// Writes the TagHelperRunner initialization code to the Writer.
        /// </summary>
        /// <param name="chunk">The <see cref="TagHelperChunk"/>.</param>
        protected override void Visit(TagHelperChunk chunk)
        {
            if (!_foundTagHelpers && !Context.Host.DesignTimeMode)
            {
                _foundTagHelpers = true;

                Writer
                .WriteStartAssignment(CSharpTagHelperCodeRenderer.RunnerVariableName)
                .Write(CSharpTagHelperCodeRenderer.RunnerVariableName)
                .Write(" ?? ")
                .WriteStartNewObject(_tagHelperContext.RunnerTypeName)
                .WriteEndMethodInvocation();
            }
        }
Пример #8
0
        private static TagHelperChunk GetViewComponentTagHelperChunk(string name, bool visitedTagHelperChunks)
        {
            var typeName = visitedTagHelperChunks ? $"{_testNamespace}.{_testClass}.{name}Type" : $"{name}Type";

            var attribute = new TagHelperAttributeDescriptor
            {
                Name         = "attribute",
                PropertyName = "Attribute",
                TypeName     = typeof(string).FullName
            };

            var requiredAttribute = new TagHelperRequiredAttributeDescriptor
            {
                Name = "Attribute"
            };

            var tagHelperDescriptor = new TagHelperDescriptor
            {
                AssemblyName = $"{name}Assembly",
                TagName      = name.ToLowerInvariant(),
                TypeName     = typeName,
                Attributes   = new[]
                {
                    attribute
                },
                RequiredAttributes = new[]
                {
                    requiredAttribute
                }
            };

            tagHelperDescriptor.PropertyBag.Add(
                ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey,
                name);

            var tagHelperChunk = new TagHelperChunk(
                $"vc:{name.ToLowerInvariant()}",
                TagMode.SelfClosing,
                new List <TagHelperAttributeTracker>(),
                new[]
            {
                tagHelperDescriptor
            });

            return(tagHelperChunk);
        }
Пример #9
0
        protected override void Visit(TagHelperChunk chunk)
        {
            using (_context.Builder.BuildBlock <RenderTagHelper>(renderTagHelper =>
            {
                renderTagHelper.DocumentLocation = CreateMappingLocation(chunk.Start, chunk.Association.Length);
            }))
            {
                AddTagHelperStructure(chunk.TagName, chunk.TagMode, chunk.Children);

                var descriptors = chunk.Descriptors.Distinct(TypeBasedTagHelperDescriptorComparer.Default);
                AddTagHelperCreation(descriptors);

                AddTagHelperAttributes(chunk.Attributes, descriptors);

                AddExecuteTagHelpers();
            }
        }
        protected override void Visit(TagHelperChunk chunk)
        {
            // We only want to setup tag helper manager fields if there are tag helpers, and only once
            if (!_foundTagHelpers)
            {
                _foundTagHelpers = true;

                // We want to hide declared TagHelper fields so they cannot be stepped over via a debugger.
                Writer.WriteLineHiddenDirective();

                // Runtime fields aren't useful during design time.
                if (!Context.Host.DesignTimeMode)
                {
                    WritePrivateField(typeof(TextWriter).FullName,
                                      CSharpTagHelperCodeRenderer.StringValueBufferVariableName,
                                      value: null);

                    WritePrivateField(_tagHelperContext.ExecutionContextTypeName,
                                      CSharpTagHelperCodeRenderer.ExecutionContextVariableName,
                                      value: null);

                    WritePrivateField(_tagHelperContext.RunnerTypeName,
                                      CSharpTagHelperCodeRenderer.RunnerVariableName,
                                      "new " + _tagHelperContext.RunnerTypeName + "()");

                    WritePrivateField(_tagHelperContext.ScopeManagerTypeName,
                                      CSharpTagHelperCodeRenderer.ScopeManagerVariableName,
                                      "new " + _tagHelperContext.ScopeManagerTypeName + "()");
                }
            }

            foreach (var descriptor in chunk.Descriptors)
            {
                if (!_declaredTagHelpers.Contains(descriptor.TypeName))
                {
                    _declaredTagHelpers.Add(descriptor.TypeName);

                    WritePrivateField(descriptor.TypeName,
                                      CSharpTagHelperCodeRenderer.GetVariableName(descriptor),
                                      value: null);
                }
            }

            // We need to dive deeper to ensure we pick up any nested tag helpers.
            Accept(chunk.Children);
        }
Пример #11
0
        private static TagHelperChunk GetTagHelperChunk(string name)
        {
            var tagHelperChunk = new TagHelperChunk(
                name.ToLowerInvariant(),
                TagMode.SelfClosing,
                new List <TagHelperAttributeTracker>(),
                new List <TagHelperDescriptor>
            {
                new TagHelperDescriptor
                {
                    AssemblyName = $"{name}Assembly",
                    TagName      = name.ToLowerInvariant(),
                    TypeName     = $"{name}Type",
                }
            });

            return(tagHelperChunk);
        }
Пример #12
0
        protected override void Visit(TagHelperChunk chunk)
        {
            foreach (var descriptor in chunk.Descriptors)
            {
                string shortName;
                if (descriptor.PropertyBag.TryGetValue(
                        ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey,
                        out shortName))
                {
                    var typeName = $"__Generated__{shortName}ViewComponentTagHelper";

                    if (_writtenViewComponents.Add(typeName))
                    {
                        WriteClass(descriptor);
                    }
                }
            }
        }
        private void RenderTagHelperOutput(TagHelperChunk chunk)
        {
            var tagHelperOutputAccessor =
                $"{ExecutionContextVariableName}.{_tagHelperContext.ExecutionContextOutputPropertyName}";

            if (ContainsChildContent(chunk.Children))
            {
                _writer
                .Write("if (!")
                .Write(tagHelperOutputAccessor)
                .Write(".")
                .Write(_tagHelperContext.TagHelperOutputIsContentModifiedPropertyName)
                .WriteLine(")");

                using (_writer.BuildScope())
                {
                    _writer
                    .Write("await ")
                    .WriteInstanceMethodInvocation(
                        ExecutionContextVariableName,
                        _tagHelperContext.ExecutionContextSetOutputContentAsyncMethodName);
                }
            }

            _writer
            .WriteStartInstrumentationContext(_context, chunk.Association, isLiteral: false);

            if (!string.IsNullOrEmpty(_context.TargetWriterName))
            {
                _writer
                .WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteToMethodName)
                .Write(_context.TargetWriterName)
                .WriteParameterSeparator();
            }
            else
            {
                _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteMethodName);
            }

            _writer
            .Write(tagHelperOutputAccessor)
            .WriteEndMethodInvocation()
            .WriteEndInstrumentationContext(_context);
        }
Пример #14
0
        /// <summary>
        /// Renders the code for the given <paramref name="chunk"/>.
        /// </summary>
        /// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
        public void RenderTagHelper(TagHelperChunk chunk)
        {
            // Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when
            // multiple HtmlTargetElement attributes are on a TagHelper type and matches overlap for an HTML element.
            // Having more than one descriptor with the same TagHelper type results in generated code that runs
            // the same TagHelper X many times (instead of once) over a single HTML element.
            var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeBasedTagHelperDescriptorComparer.Default);

            RenderBeginTagHelperScope(chunk.TagName, chunk.TagMode, chunk.Children);

            RenderTagHelpersCreation(chunk, tagHelperDescriptors);

            RenderAttributes(chunk.Attributes, tagHelperDescriptors);

            // No need to run anything in design time mode.
            if (!_designTimeMode)
            {
                RenderRunTagHelpers();
                RenderTagHelperOutput(chunk);
                RenderEndTagHelpersScope();
            }
        }
Пример #15
0
        protected override void Visit(TagHelperChunk chunk)
        {
            if (Context.Host.DesignTimeMode)
            {
                return;
            }

            if (!_foundTagHelpers)
            {
                _foundTagHelpers = true;

                foreach (var tagHelperRuntimeNamespace in TagHelpersRuntimeNamespaces)
                {
                    if (ImportedUsings.Add(tagHelperRuntimeNamespace))
                    {
                        // If we find TagHelpers then we need to add the TagHelper runtime namespaces to our list of
                        // usings.
                        Writer.WriteUsing(tagHelperRuntimeNamespace);
                    }
                }
            }
        }
Пример #16
0
        /// <summary>
        /// Renders the code for the given <paramref name="chunk"/>.
        /// </summary>
        /// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
        public void RenderTagHelper(TagHelperChunk chunk)
        {
            // Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when
            // multiple TargetElement attributes are on a TagHelper type and matches overlap for an HTML element.
            // Having more than one descriptor with the same TagHelper type results in generated code that runs
            // the same TagHelper X many times (instead of once) over a single HTML element.
            var tagHelperDescriptors = chunk.Descriptors.Distinct(TypeBasedTagHelperDescriptorComparer.Default);

            RenderBeginTagHelperScope(chunk.TagName, chunk.SelfClosing, chunk.Children);

            RenderTagHelpersCreation(chunk, tagHelperDescriptors);

            RenderAttributes(chunk.Attributes, tagHelperDescriptors);

            // No need to run anything in design time mode.
            if (!_designTimeMode)
            {
                RenderRunTagHelpers();
                RenderWriteTagHelperMethodCall(chunk);
                RenderEndTagHelpersScope();
            }
        }
Пример #17
0
        protected override void Visit(TagHelperChunk chunk)
        {
            if (!_foundTagHelpers)
            {
                _foundTagHelpers = true;
                var declareTagHelperFields = new DeclareTagHelperFields
                {
                    UsedTagHelperTypeNames = _usedTagHelpers
                };

                _context.Builder.Add(declareTagHelperFields);
            }

            foreach (var descriptor in chunk.Descriptors)
            {
                if (!_usedTagHelpers.Contains(descriptor.TypeName))
                {
                    _usedTagHelpers.Add(descriptor.TypeName);
                }
            }

            Accept(chunk.Children);
        }
Пример #18
0
        private void RenderWriteTagHelperMethodCall(TagHelperChunk chunk)
        {
            _writer
            .WriteStartInstrumentationContext(_context, chunk.Association, isLiteral: false)
            .Write("await ");

            if (!string.IsNullOrEmpty(_context.TargetWriterName))
            {
                _writer
                .WriteStartMethodInvocation(_tagHelperContext.WriteTagHelperToAsyncMethodName)
                .Write(_context.TargetWriterName)
                .WriteParameterSeparator();
            }
            else
            {
                _writer.WriteStartMethodInvocation(_tagHelperContext.WriteTagHelperAsyncMethodName);
            }

            _writer
            .Write(ExecutionContextVariableName)
            .WriteEndMethodInvocation()
            .WriteEndInstrumentationContext(_context);
        }
Пример #19
0
        /// <summary>
        /// Writes the TagHelperRunner initialization code to the Writer.
        /// </summary>
        /// <param name="chunk">The <see cref="TagHelperChunk"/>.</param>
        protected override void Visit(TagHelperChunk chunk)
        {
            if (!_foundTagHelpers && !Context.Host.DesignTimeMode)
            {
                _foundTagHelpers = true;

                Writer
                .WriteStartAssignment(CSharpTagHelperCodeRenderer.RunnerVariableName)
                .Write(CSharpTagHelperCodeRenderer.RunnerVariableName)
                .Write(" ?? ")
                .WriteStartNewObject("global::" + _tagHelperContext.RunnerTypeName)
                .WriteEndMethodInvocation();

                Writer
                .WriteStartAssignment(CSharpTagHelperCodeRenderer.ScopeManagerVariableName)
                .Write(CSharpTagHelperCodeRenderer.ScopeManagerVariableName)
                .Write(" ?? ")
                .WriteStartNewObject("global::" + _tagHelperContext.ScopeManagerTypeName)
                .Write(_tagHelperContext.StartTagHelperWritingScopeMethodName)
                .WriteParameterSeparator()
                .Write(_tagHelperContext.EndTagHelperWritingScopeMethodName)
                .WriteEndMethodInvocation();
            }
        }
        private void PreAllocateUnboundTagHelperAttributes(TagHelperChunk chunk)
        {
            var boundAttributes = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            for (var i = 0; i < chunk.Attributes.Count; i++)
            {
                var attribute = chunk.Attributes[i];
                var hasAssociatedDescriptors = chunk.Descriptors.Any(descriptor =>
                                                                     descriptor.Attributes.Any(attributeDescriptor => attributeDescriptor.IsNameMatch(attribute.Key)));

                // If there's no descriptors associated or we're hitting a bound attribute a second time.
                if (!hasAssociatedDescriptors || !boundAttributes.Add(attribute.Key))
                {
                    string preAllocatedAttributeVariableName = null;

                    if (attribute.Value == null)
                    {
                        var preAllocatedAttributeKey = new TagHelperAttributeKey(attribute.Key, value: null);
                        if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName))
                        {
                            Writer
                            .Write("private static readonly global::")
                            .Write(_tagHelperContext.TagHelperAttributeTypeName)
                            .Write(" ")
                            .Write(preAllocatedAttributeVariableName)
                            .Write(" = ")
                            .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName)
                            .WriteStringLiteral(attribute.Key)
                            .WriteEndMethodInvocation();
                        }
                    }
                    else
                    {
                        string plainText;
                        if (CSharpTagHelperCodeRenderer.TryGetPlainTextValue(attribute.Value, out plainText))
                        {
                            var preAllocatedAttributeKey = new TagHelperAttributeKey(attribute.Key, plainText);
                            if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName))
                            {
                                Writer
                                .Write("private static readonly global::")
                                .Write(_tagHelperContext.TagHelperAttributeTypeName)
                                .Write(" ")
                                .Write(preAllocatedAttributeVariableName)
                                .Write(" = ")
                                .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName)
                                .WriteStringLiteral(attribute.Key)
                                .WriteParameterSeparator()
                                .WriteStartNewObject("global::" + _tagHelperContext.EncodedHtmlStringTypeName)
                                .WriteStringLiteral(plainText)
                                .WriteEndMethodInvocation(endLine: false)
                                .WriteEndMethodInvocation();
                            }
                        }
                    }

                    if (preAllocatedAttributeVariableName != null)
                    {
                        chunk.Attributes[i] = new KeyValuePair <string, Chunk>(
                            attribute.Key,
                            new PreallocatedTagHelperAttributeChunk
                        {
                            AttributeVariableAccessor = preAllocatedAttributeVariableName
                        });
                    }
                }
            }
        }
Пример #21
0
        private void RenderTagHelpersCreation(
            TagHelperChunk chunk,
            IEnumerable <TagHelperDescriptor> tagHelperDescriptors)
        {
            // This is to maintain value accessors for attributes when creating the TagHelpers.
            // Ultimately it enables us to do scenarios like this:
            // myTagHelper1.Foo = DateTime.Now;
            // myTagHelper2.Foo = myTagHelper1.Foo;
            var htmlAttributeValues = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            foreach (var tagHelperDescriptor in tagHelperDescriptors)
            {
                var tagHelperVariableName = GetVariableName(tagHelperDescriptor);

                // Create the tag helper
                _writer.WriteStartAssignment(tagHelperVariableName)
                .WriteStartMethodInvocation(_tagHelperContext.CreateTagHelperMethodName,
                                            tagHelperDescriptor.TypeName)
                .WriteEndMethodInvocation();

                // Execution contexts and throwing errors for null dictionary properties are a runtime feature.
                if (_designTimeMode)
                {
                    continue;
                }

                _writer.WriteInstanceMethodInvocation(
                    ExecutionContextVariableName,
                    _tagHelperContext.ExecutionContextAddMethodName,
                    tagHelperVariableName);

                // Track dictionary properties we have confirmed are non-null.
                var confirmedDictionaries = new HashSet <string>(StringComparer.Ordinal);

                // Ensure that all created TagHelpers have initialized dictionary bound properties which are used
                // via TagHelper indexers.
                foreach (var chunkAttribute in chunk.Attributes)
                {
                    var associatedAttributeDescriptor = tagHelperDescriptor.Attributes.FirstOrDefault(
                        attributeDescriptor => attributeDescriptor.IsNameMatch(chunkAttribute.Key));

                    if (associatedAttributeDescriptor != null &&
                        associatedAttributeDescriptor.IsIndexer &&
                        confirmedDictionaries.Add(associatedAttributeDescriptor.PropertyName))
                    {
                        // Throw a reasonable Exception at runtime if the dictionary property is null.
                        _writer
                        .Write("if (")
                        .Write(tagHelperVariableName)
                        .Write(".")
                        .Write(associatedAttributeDescriptor.PropertyName)
                        .WriteLine(" == null)");
                        using (_writer.BuildScope())
                        {
                            // System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName
                            // of InvalidOperationException type.
                            _writer
                            .Write("throw ")
                            .WriteStartNewObject(nameof(InvalidOperationException))
                            .WriteStartMethodInvocation(_tagHelperContext.FormatInvalidIndexerAssignmentMethodName)
                            .WriteStringLiteral(chunkAttribute.Key)
                            .WriteParameterSeparator()
                            .WriteStringLiteral(tagHelperDescriptor.TypeName)
                            .WriteParameterSeparator()
                            .WriteStringLiteral(associatedAttributeDescriptor.PropertyName)
                            .WriteEndMethodInvocation(endLine: false)       // End of method call
                            .WriteEndMethodInvocation(endLine: true);       // End of new expression / throw statement
                        }
                    }
                }
            }
        }
 protected virtual void Visit(TagHelperChunk chunk)
 {
 }
Пример #23
0
        private void PreAllocateTagHelperAttributes(TagHelperChunk chunk)
        {
            var boundAttributes = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            for (var i = 0; i < chunk.Attributes.Count; i++)
            {
                var attribute = chunk.Attributes[i];
                var associatedAttributeDescriptors = chunk.Descriptors.SelectMany(descriptor => descriptor.Attributes)
                                                     .Where(attributeDescriptor => attributeDescriptor.IsNameMatch(attribute.Name));

                // If there's no descriptors associated or is a repeated attribute with same name as a bound attribute,
                // it is considered as an unbound attribute.
                var isUnBoundAttribute = !associatedAttributeDescriptors.Any() || !boundAttributes.Add(attribute.Name);

                // Perf: We will preallocate TagHelperAttribute for unbound attributes and simple bound string valued attributes.
                if (isUnBoundAttribute || CanPreallocateBoundAttribute(associatedAttributeDescriptors, attribute))
                {
                    string preAllocatedAttributeVariableName = null;

                    if (attribute.ValueStyle == HtmlAttributeValueStyle.Minimized)
                    {
                        Debug.Assert(attribute.Value == null);

                        var preAllocatedAttributeKey = new TagHelperAttributeKey(
                            attribute.Name,
                            value: null,
                            unBoundAttribute: isUnBoundAttribute,
                            valueStyle: attribute.ValueStyle);
                        if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName))
                        {
                            Writer
                            .Write("private static readonly global::")
                            .Write(_tagHelperContext.TagHelperAttributeTypeName)
                            .Write(" ")
                            .Write(preAllocatedAttributeVariableName)
                            .Write(" = ")
                            .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName)
                            .WriteStringLiteral(attribute.Name)
                            .WriteEndMethodInvocation();
                        }
                    }
                    else
                    {
                        Debug.Assert(attribute.Value != null);

                        string plainText;
                        if (CSharpTagHelperCodeRenderer.TryGetPlainTextValue(attribute.Value, out plainText))
                        {
                            var preAllocatedAttributeKey = new TagHelperAttributeKey(attribute.Name, plainText, isUnBoundAttribute, attribute.ValueStyle);
                            if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName))
                            {
                                Writer
                                .Write("private static readonly global::")
                                .Write(_tagHelperContext.TagHelperAttributeTypeName)
                                .Write(" ")
                                .Write(preAllocatedAttributeVariableName)
                                .Write(" = ")
                                .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName)
                                .WriteStringLiteral(attribute.Name)
                                .WriteParameterSeparator();

                                if (isUnBoundAttribute)
                                {
                                    // For unbound attributes, we need to create HtmlString.
                                    Writer
                                    .WriteStartNewObject("global::" + _tagHelperContext.EncodedHtmlStringTypeName)
                                    .WriteStringLiteral(plainText)
                                    .WriteEndMethodInvocation(endLine: false);
                                }
                                else
                                {
                                    Writer.WriteStringLiteral(plainText);
                                }

                                Writer
                                .WriteParameterSeparator()
                                .Write($"global::{typeof(HtmlAttributeValueStyle).FullName}.{attribute.ValueStyle}")
                                .WriteEndMethodInvocation();
                            }
                        }
                    }

                    if (preAllocatedAttributeVariableName != null)
                    {
                        chunk.Attributes[i] = new TagHelperAttributeTracker(
                            attribute.Name,
                            new PreallocatedTagHelperAttributeChunk
                        {
                            AttributeVariableAccessor = preAllocatedAttributeVariableName
                        },
                            attribute.ValueStyle);
                    }
                }
            }
        }
Пример #24
0
        private void RenderTagHelperOutput(TagHelperChunk chunk)
        {
            var tagHelperOutputAccessor =
                $"{ExecutionContextVariableName}.{_tagHelperContext.ExecutionContextOutputPropertyName}";

            if (ContainsChildContent(chunk.Children))
            {
                _writer
                    .Write("if (!")
                    .Write(tagHelperOutputAccessor)
                    .Write(".")
                    .Write(_tagHelperContext.TagHelperOutputIsContentModifiedPropertyName)
                    .WriteLine(")");

                using (_writer.BuildScope())
                {
                    _writer
                        .Write("await ")
                        .WriteInstanceMethodInvocation(
                            ExecutionContextVariableName,
                            _tagHelperContext.ExecutionContextSetOutputContentAsyncMethodName);
                }
            }

            _writer
                .WriteStartInstrumentationContext(_context, chunk.Association, isLiteral: false);

            if (!string.IsNullOrEmpty(_context.TargetWriterName))
            {
                _writer
                    .WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteToMethodName)
                    .Write(_context.TargetWriterName)
                    .WriteParameterSeparator();
            }
            else
            {
                _writer.WriteStartMethodInvocation(_context.Host.GeneratedClassContext.WriteMethodName);
            }

            _writer
                .Write(tagHelperOutputAccessor)
                .WriteEndMethodInvocation()
                .WriteEndInstrumentationContext(_context);
        }
Пример #25
0
 protected override void Visit(TagHelperChunk chunk)
 {
 }
 protected abstract void Visit(TagHelperChunk chunk);
Пример #27
0
        /// <summary>
        /// Renders the code for the given <paramref name="chunk"/>.
        /// </summary>
        /// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
        public void RenderTagHelper(TagHelperChunk chunk)
        {
            var tagHelperDescriptors = chunk.Descriptors;

            // Find the first content behavior that doesn't have a content behavior of None.
            // The resolver restricts content behavior collisions so the first one that's not None will be
            // the content behavior we need to abide by. None can work in unison with other ContentBehaviors.
            var contentBehavior = tagHelperDescriptors.Select(descriptor => descriptor.ContentBehavior)
                                  .FirstOrDefault(
                behavior => behavior != ContentBehavior.None);

            RenderBeginTagHelperScope(chunk.TagName);

            RenderTagHelpersCreation(chunk);

            var attributeDescriptors  = tagHelperDescriptors.SelectMany(descriptor => descriptor.Attributes);
            var boundHTMLAttributes   = attributeDescriptors.Select(descriptor => descriptor.Name);
            var htmlAttributes        = chunk.Attributes;
            var unboundHTMLAttributes =
                htmlAttributes.Where(htmlAttribute => !boundHTMLAttributes.Contains(htmlAttribute.Key,
                                                                                    StringComparer.OrdinalIgnoreCase));

            RenderUnboundHTMLAttributes(unboundHTMLAttributes);

            switch (contentBehavior)
            {
            case ContentBehavior.None:
                RenderRunTagHelpers(bufferedBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
                RenderTagHelperBody(chunk.Children, bufferBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
                break;

            case ContentBehavior.Append:
                RenderRunTagHelpers(bufferedBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
                RenderTagHelperBody(chunk.Children, bufferBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
                RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
                break;

            case ContentBehavior.Prepend:
                RenderRunTagHelpers(bufferedBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
                RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
                RenderTagHelperBody(chunk.Children, bufferBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
                break;

            case ContentBehavior.Replace:
                RenderRunTagHelpers(bufferedBody: false);
                RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
                RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
                RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
                break;

            case ContentBehavior.Modify:
                RenderTagHelperBody(chunk.Children, bufferBody: true);
                RenderRunTagHelpers(bufferedBody: true);
                RenderTagOutput(_tagHelperContext.OutputGenerateStartTagMethodName);
                RenderTagOutput(_tagHelperContext.OutputGenerateContentMethodName);
                RenderTagOutput(_tagHelperContext.OutputGenerateEndTagMethodName);
                break;
            }

            RenderEndTagHelpersScope();
        }
Пример #28
0
 protected override void Visit(TagHelperChunk chunk)
 {
     TagHelperRenderer.RenderTagHelper(chunk);
 }
Пример #29
0
        private void RenderTagHelpersCreation(
            TagHelperChunk chunk,
            IEnumerable<TagHelperDescriptor> tagHelperDescriptors)
        {
            // This is to maintain value accessors for attributes when creating the TagHelpers.
            // Ultimately it enables us to do scenarios like this:
            // myTagHelper1.Foo = DateTime.Now;
            // myTagHelper2.Foo = myTagHelper1.Foo;
            var htmlAttributeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            foreach (var tagHelperDescriptor in tagHelperDescriptors)
            {
                var tagHelperVariableName = GetVariableName(tagHelperDescriptor);

                // Create the tag helper
                _writer.WriteStartAssignment(tagHelperVariableName)
                       .WriteStartMethodInvocation(
                            _tagHelperContext.CreateTagHelperMethodName,
                            "global::" + tagHelperDescriptor.TypeName)
                       .WriteEndMethodInvocation();

                // Execution contexts and throwing errors for null dictionary properties are a runtime feature.
                if (_designTimeMode)
                {
                    continue;
                }

                _writer.WriteInstanceMethodInvocation(
                    ExecutionContextVariableName,
                    _tagHelperContext.ExecutionContextAddMethodName,
                    tagHelperVariableName);

                // Track dictionary properties we have confirmed are non-null.
                var confirmedDictionaries = new HashSet<string>(StringComparer.Ordinal);

                // Ensure that all created TagHelpers have initialized dictionary bound properties which are used
                // via TagHelper indexers.
                foreach (var chunkAttribute in chunk.Attributes)
                {
                    var associatedAttributeDescriptor = tagHelperDescriptor.Attributes.FirstOrDefault(
                        attributeDescriptor => attributeDescriptor.IsNameMatch(chunkAttribute.Name));

                    if (associatedAttributeDescriptor != null &&
                        associatedAttributeDescriptor.IsIndexer &&
                        confirmedDictionaries.Add(associatedAttributeDescriptor.PropertyName))
                    {
                        // Throw a reasonable Exception at runtime if the dictionary property is null.
                        _writer
                            .Write("if (")
                            .Write(tagHelperVariableName)
                            .Write(".")
                            .Write(associatedAttributeDescriptor.PropertyName)
                            .WriteLine(" == null)");
                        using (_writer.BuildScope())
                        {
                            // System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName
                            // of InvalidOperationException type.
                            _writer
                                .Write("throw ")
                                .WriteStartNewObject(nameof(InvalidOperationException))
                                .WriteStartMethodInvocation(_tagHelperContext.FormatInvalidIndexerAssignmentMethodName)
                                .WriteStringLiteral(chunkAttribute.Name)
                                .WriteParameterSeparator()
                                .WriteStringLiteral(tagHelperDescriptor.TypeName)
                                .WriteParameterSeparator()
                                .WriteStringLiteral(associatedAttributeDescriptor.PropertyName)
                                .WriteEndMethodInvocation(endLine: false)   // End of method call
                                .WriteEndMethodInvocation(endLine: true);   // End of new expression / throw statement
                        }
                    }
                }
            }
        }