/// <summary>
        /// Called during Razor's code generation process to generate code that instantiates the value of the tag
        /// helper's property. Last value written should not be or end with a semicolon.
        /// </summary>
        /// <param name="attributeDescriptor">
        /// The <see cref="TagHelperAttributeDescriptor"/> to generate code for.
        /// </param>
        /// <param name="writer">The <see cref="CSharpCodeWriter"/> that's used to write code.</param>
        /// <param name="context">A <see cref="Chunks.Generators.ChunkGeneratorContext"/> instance that contains
        /// information about the current code generation process.</param>
        /// <param name="renderAttributeValue">
        /// <see cref="Action"/> that renders the raw value of the HTML attribute.
        /// </param>
        /// <param name="complexValue">
        /// Indicates whether or not the source attribute value contains more than simple text. <c>false</c> for plain
        /// C# expressions e.g. <c>"PropertyName"</c>. <c>true</c> if the attribute value contain at least one in-line
        /// Razor construct e.g. <c>"@(@readonly)"</c>.
        /// </param>
        public virtual void RenderAttributeValue(
            TagHelperAttributeDescriptor attributeDescriptor,
            CSharpCodeWriter writer,
            CodeGeneratorContext context,
            Action<CSharpCodeWriter> renderAttributeValue,
            bool complexValue)
        {
            if (attributeDescriptor == null)
            {
                throw new ArgumentNullException(nameof(attributeDescriptor));
            }

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

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

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

            renderAttributeValue(writer);
        }
        public CSharpDisableWarningScope(CSharpCodeWriter writer, int warningNumber)
        {
            _writer = writer;
            _warningNumber = warningNumber;

            _writer.WritePragma("warning disable " + _warningNumber);
        }
Example #3
0
        public void Visit_GeneratesProperties_ForInjectChunks()
        {
            // Arrange
            var expected =
            @"[ActivateAttribute]
            public MyType1 MyPropertyName1 { get; private set; }
            [ActivateAttribute]
            public MyType2 @MyPropertyName2 { get; private set; }
            ";
            var writer = new CSharpCodeWriter();
            var context = CreateContext();

            var visitor = new InjectChunkVisitor(writer, context, "ActivateAttribute");
            var factory = SpanFactory.CreateCsHtml();
            var node = (Span)factory.Code("Some code")
                                    .As(new InjectParameterGenerator("MyType", "MyPropertyName"));

            // Act
            visitor.Accept(new Chunk[]
            {
                new LiteralChunk(),
                new InjectChunk("MyType1", "MyPropertyName1") { Association = node },
                new InjectChunk("MyType2", "@MyPropertyName2") { Association = node }
            });
            var code = writer.GenerateCode();

            // Assert
            Assert.Equal(expected, code);
        }
        /// <summary>
        /// Instantiates a new <see cref="CSharpTagHelperCodeRenderer"/>.
        /// </summary>
        /// <param name="bodyVisitor">The <see cref="IChunkVisitor"/> used to render chunks found in the body.</param>
        /// <param name="writer">The <see cref="CSharpCodeWriter"/> used to write code.</param>
        /// <param name="context">A <see cref="CodeGeneratorContext"/> instance that contains information about
        /// the current code generation process.</param>
        public CSharpTagHelperCodeRenderer(
            IChunkVisitor bodyVisitor,
            CSharpCodeWriter writer,
            CodeGeneratorContext context)
        {
            if (bodyVisitor == null)
            {
                throw new ArgumentNullException(nameof(bodyVisitor));
            }

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

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

            _bodyVisitor = bodyVisitor;
            _writer = writer;
            _context = context;
            _tagHelperContext = context.Host.GeneratedClassContext.GeneratedTagHelperContext;
            _designTimeMode = context.Host.DesignTimeMode;

            _literalBodyVisitor = new CSharpLiteralCodeVisitor(this, writer, context);
            _attributeCodeVisitor = new TagHelperAttributeCodeVisitor(writer, context);
            AttributeValueCodeRenderer = new TagHelperAttributeValueCodeRenderer();
        }
Example #5
0
 protected override CSharpCodeVisitor CreateCSharpCodeVisitor(
     CSharpCodeWriter writer,
     CodeGeneratorContext context)
 {
     var visitor = base.CreateCSharpCodeVisitor(writer, context);
     visitor.TagHelperRenderer = new NoUniqueIdsTagHelperCodeRenderer(visitor, writer, context);
     return visitor;
 }
        /// <inheritdoc />
        /// <remarks>If the attribute being rendered is of the type
        /// <see cref="GeneratedTagHelperAttributeContext.ModelExpressionTypeName"/>, then a model expression will be
        /// created by calling into <see cref="GeneratedTagHelperAttributeContext.CreateModelExpressionMethodName"/>.
        /// </remarks>
        public override void RenderAttributeValue(
            TagHelperAttributeDescriptor attributeDescriptor,
            CSharpCodeWriter writer,
            CodeGeneratorContext codeGeneratorContext,
            Action<CSharpCodeWriter> renderAttributeValue,
            bool complexValue)
        {
            if (attributeDescriptor == null)
            {
                throw new ArgumentNullException(nameof(attributeDescriptor));
            }

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

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

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

            if (attributeDescriptor.TypeName.Equals(_context.ModelExpressionTypeName, StringComparison.Ordinal))
            {
                writer
                    .WriteStartInstanceMethodInvocation(_context.ModelExpressionProviderPropertyName, _context.CreateModelExpressionMethodName)
                    .Write(_context.ViewDataPropertyName)
                    .WriteParameterSeparator()
                    .Write(ModelLambdaVariableName)
                    .Write(" => ");
                if (!complexValue)
                {
                    writer
                        .Write(ModelLambdaVariableName)
                        .Write(".");

                }

                renderAttributeValue(writer);

                writer.WriteEndMethodInvocation(endLine: false);
            }
            else
            {
                base.RenderAttributeValue(
                    attributeDescriptor,
                    writer,
                    codeGeneratorContext,
                    renderAttributeValue,
                    complexValue);
            }
        }
Example #7
0
        public CSharpLineMappingWriter(
            CSharpCodeWriter writer,
            SourceLocation documentLocation,
            int contentLength,
            string sourceFilename)
            : this(writer, documentLocation, contentLength)
        {
            _writePragmas = true;

            _writer.WriteLineNumberDirective(documentLocation, sourceFilename);
            _generatedLocation = _writer.GetCurrentSourceLocation();
        }
Example #8
0
        private CSharpLineMappingWriter(CSharpCodeWriter writer, bool addLineMappings)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            _writer = writer;
            _addLineMapping = addLineMappings;
            _startIndent = _writer.CurrentIndent;
            _writer.ResetIndent();
        }
Example #9
0
 private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)
 {
     if (_designTimeMode)
     {
         // There is no value buffer in design time mode but we still want to write out a value. We write a
         // value to ensure the tag helper's property type is string.
         writer.Write("string.Empty");
     }
     else
     {
         writer.Write(StringValueBufferVariableName);
     }
 }
Example #10
0
        /// <summary>
        /// Initializes a new instance of <see cref="CSharpLineMappingWriter"/> used for generation of runtime
        /// line mappings. The constructed instance of <see cref="CSharpLineMappingWriter"/> does not track
        /// mappings between the Razor content and the generated content.
        /// </summary>
        /// <param name="writer">The <see cref="CSharpCodeWriter"/> to write output to.</param>
        /// <param name="documentLocation">The <see cref="SourceLocation"/> of the Razor content being mapping.</param>
        /// <param name="sourceFileName">The input file path.</param>
        public CSharpLineMappingWriter(
            CSharpCodeWriter writer,
            SourceLocation documentLocation,
            string sourceFileName)
            : this(writer, addLineMappings : false)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            _writePragmas = true;
            _writer.WriteLineNumberDirective(documentLocation, sourceFileName);
        }
Example #11
0
        /// <summary>
        /// Initializes a new instance of <see cref="CSharpLineMappingWriter"/> used for generation of runtime
        /// line mappings. The constructed instance of <see cref="CSharpLineMappingWriter"/> does not track
        /// mappings between the Razor content and the generated content.
        /// </summary>
        /// <param name="writer">The <see cref="CSharpCodeWriter"/> to write output to.</param>
        /// <param name="documentLocation">The <see cref="SourceLocation"/> of the Razor content being mapping.</param>
        /// <param name="sourceFileName">The input file path.</param>
        public CSharpLineMappingWriter(
            CSharpCodeWriter writer,
            SourceLocation documentLocation,
            string sourceFileName)
            : this(writer, addLineMappings: false)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            _writePragmas = true;
            _writer.WriteLineNumberDirective(documentLocation, sourceFileName);
        }
Example #12
0
        protected override CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
        {
            if (Context.Host.DesignTimeMode &&
                string.Equals(
                    Path.GetFileName(Context.SourceFile),
                    ViewHierarchyUtility.ViewImportsFileName,
                    StringComparison.OrdinalIgnoreCase))
            {
                // Write a using TModel = System.Object; token during design time to make intellisense work
                writer.WriteLine($"using {ChunkHelper.TModelToken} = {typeof(object).FullName};");
            }

            return base.BuildClassDeclaration(writer);
        }
Example #13
0
        public MvcCSharpCodeVisitor(
            CSharpCodeWriter writer,
            CodeGeneratorContext context)
            : base(writer, context)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
        }
Example #14
0
        public void WriteLineNumberDirective_UsesFilePath_WhenFileInSourceLocationIsNull()
        {
            // Arrange
            var filePath       = "some-path";
            var writer         = new CSharpCodeWriter();
            var expected       = $"#line 5 \"{filePath}\"" + writer.NewLine;
            var sourceLocation = new SourceLocation(10, 4, 3);

            // Act
            writer.WriteLineNumberDirective(sourceLocation, filePath);
            var code = writer.GenerateCode();

            // Assert
            Assert.Equal(expected, code);
        }
Example #15
0
        protected virtual CSharpCodeVisitor CreateCSharpCodeVisitor(
            CSharpCodeWriter writer,
            CodeGeneratorContext context)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

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

            return(new CSharpCodeVisitor(writer, context));
        }
Example #16
0
        protected override void BuildConstructor(CSharpCodeWriter writer)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

            base.BuildConstructor(writer);

            writer.WriteLineHiddenDirective();

            var injectVisitor = new InjectChunkVisitor(writer, Context, _injectAttribute);
            injectVisitor.Accept(Context.ChunkTreeBuilder.Root.Children);

            writer.WriteLine();
            writer.WriteLineHiddenDirective();
        }
 private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)
 {
     if (_designTimeMode)
     {
         // There is no value buffer in design time mode but we still want to write out a value. We write a
         // value to ensure the tag helper's property type is string.
         writer.Write("string.Empty");
     }
     else
     {
         writer.WriteInstanceMethodInvocation(
             StringValueBufferVariableName,
             _tagHelperContext.TagHelperContentGetContentMethodName,
             endLine: false,
             parameters: _tagHelperContext.HtmlEncoderPropertyName);
     }
 }
Example #18
0
        public void Visit_IgnoresNonInjectChunks()
        {
            // Arrange
            var writer = new CSharpCodeWriter();
            var context = CreateContext();

            var visitor = new InjectChunkVisitor(writer, context, "ActivateAttribute");

            // Act
            visitor.Accept(new Chunk[]
            {
                new LiteralChunk(),
                new CodeAttributeChunk()
            });
            var code = writer.GenerateCode();

            // Assert
            Assert.Empty(code);
        }
        public void RenderAttributeValue_RendersModelExpressionsCorrectly(
            string modelExpressionType,
            string propertyType,
            string expectedValue)
        {
            // Arrange
            var renderer = new MvcTagHelperAttributeValueCodeRenderer(
                new GeneratedTagHelperAttributeContext
                {
                    ModelExpressionTypeName = modelExpressionType,
                    CreateModelExpressionMethodName = "SomeMethod",
                    ModelExpressionProviderPropertyName = "Provider",
                    ViewDataPropertyName = "ViewData"
                });
            var attributeDescriptor = new TagHelperAttributeDescriptor
            {
                Name = "MyAttribute",
                PropertyName = "SomeProperty",
                TypeName = propertyType,
            };
            var writer = new CSharpCodeWriter();
            var generatorContext = new ChunkGeneratorContext(
                host: null,
                className: string.Empty,
                rootNamespace: string.Empty,
                sourceFile: string.Empty,
                shouldGenerateLinePragmas: true);
            var errorSink = new ErrorSink();
            var context = new CodeGeneratorContext(generatorContext, errorSink);

            // Act
            renderer.RenderAttributeValue(attributeDescriptor, writer, context,
            (codeWriter) =>
            {
                codeWriter.Write("MyValue");
            },
            complexValue: false);

            // Assert
            Assert.Equal(expectedValue, writer.GenerateCode());
        }
        public void WriterConstructedWithContentLength_AddsLineMappings_OnDispose()
        {
            // Arrange
            var location = new SourceLocation(10, 15, 20);
            var expected = new LineMapping(
                new MappingLocation(location, 30),
                new MappingLocation(new SourceLocation(0, 0, 0), 11));
            var writer = new CSharpCodeWriter();

            // Act
            using (var mappingWriter = new CSharpLineMappingWriter(writer, location, 30))
            {
                writer.Write("Hello world");
            }

            // Assert
            Assert.Equal("Hello world", writer.GenerateCode());
            var mapping = Assert.Single(writer.LineMappingManager.Mappings);

            Assert.Equal(expected, mapping);
        }
Example #21
0
        public InjectChunkVisitor(
            CSharpCodeWriter writer,
            CodeGeneratorContext context,
            string injectAttributeName)
            : base(writer, context)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

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

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

            _injectAttribute = "[" + injectAttributeName + "]";
        }
Example #22
0
        protected override CSharpDesignTimeCodeVisitor CreateCSharpDesignTimeCodeVisitor(
            CSharpCodeVisitor csharpCodeVisitor,
            CSharpCodeWriter writer,
            CodeGeneratorContext context)
        {
            if (csharpCodeVisitor == null)
            {
                throw new ArgumentNullException(nameof(csharpCodeVisitor));
            }

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

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

            return new MvcCSharpDesignTimeCodeVisitor(csharpCodeVisitor, writer, context);
        }
 private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)
 {
     if (_designTimeMode)
     {
         // There is no value buffer in design time mode but we still want to write out a value. We write a
         // value to ensure the tag helper's property type is string.
         writer.Write("string.Empty");
     }
     else
     {
         writer.Write(StringValueBufferVariableName);
     }
 }
Example #24
0
        protected override CSharpCodeVisitor CreateCSharpCodeVisitor(
            CSharpCodeWriter writer,
            CodeGeneratorContext context)
        {
            if (writer == null)
            {
                throw new ArgumentNullException(nameof(writer));
            }

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

            var csharpCodeVisitor = base.CreateCSharpCodeVisitor(writer, context);

            csharpCodeVisitor.TagHelperRenderer.AttributeValueCodeRenderer =
                new MvcTagHelperAttributeValueCodeRenderer(_tagHelperAttributeContext);

            return csharpCodeVisitor;
        }
Example #25
0
 /// <summary>
 /// Provides an entry point to append code (after execute content) to a generated Razor class.
 /// </summary>
 /// <param name="writer">The <see cref="CSharpCodeWriter"/> to receive the additional content.</param>
 /// <param name="chunks">The list of <see cref="Chunk"/>s for the generated program.</param>
 protected virtual void BuildAfterExecuteContent(CSharpCodeWriter writer, IList <Chunk> chunks)
 {
 }
Example #26
0
 public CSharpDisableWarningScope(CSharpCodeWriter writer) : this(writer, 219)
 {
 }
Example #27
0
 public CSharpLineMappingWriter(CSharpCodeWriter writer, SourceLocation documentLocation, int contentLength)
     : this(writer, addLineMappings: true)
 {
     _documentMapping = new MappingLocation(documentLocation, contentLength);
     _generatedLocation = _writer.GetCurrentSourceLocation();
 }
Example #28
0
 public CSharpDisableWarningScope(CSharpCodeWriter writer) : this(writer, 219)
 { }
Example #29
0
 public NoUniqueIdsTagHelperCodeRenderer(IChunkVisitor bodyVisitor,
     CSharpCodeWriter writer,
     CodeGeneratorContext context)
     : base(bodyVisitor, writer, context)
 {
 }
 public CSharpLiteralCodeVisitor(
     CSharpTagHelperCodeRenderer tagHelperRenderer,
     CSharpCodeWriter writer,
     CodeGeneratorContext context)
     : base(writer, context)
 {
     // Ensure that no matter how this class is used, we don't create numerous CSharpTagHelperCodeRenderer
     // instances.
     TagHelperRenderer = tagHelperRenderer;
 }
 public TagHelperAttributeCodeVisitor(
     CSharpCodeWriter writer,
     CodeGeneratorContext context)
     : base(writer, context)
 {
 }
 public TagHelperAttributeCodeVisitor(
     CSharpCodeWriter writer,
     CodeGeneratorContext context)
     : base(writer, context)
 {
 }
 private static TrackingUniqueIdsTagHelperCodeRenderer CreateCodeRenderer()
 {
     var writer = new CSharpCodeWriter();
     var codeGeneratorContext = CreateContext();
     var visitor = new CSharpCodeVisitor(writer, codeGeneratorContext);
     var codeRenderer = new TrackingUniqueIdsTagHelperCodeRenderer(
         visitor,
         writer,
         codeGeneratorContext);
     visitor.TagHelperRenderer = codeRenderer;
     return codeRenderer;
 }
Example #34
0
 public CSharpLineMappingWriter(CSharpCodeWriter writer, SourceLocation documentLocation, int contentLength)
     : this(writer, addLineMappings : true)
 {
     _documentMapping   = new MappingLocation(documentLocation, contentLength);
     _generatedLocation = _writer.GetCurrentSourceLocation();
 }
 private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)
 {
     if (_designTimeMode)
     {
         // There is no value buffer in design time mode but we still want to write out a value. We write a
         // value to ensure the tag helper's property type is string.
         writer.Write("string.Empty");
     }
     else
     {
         writer.WriteInstanceMethodInvocation(
             StringValueBufferVariableName,
             _tagHelperContext.TagHelperContentGetContentMethodName,
             endLine: false,
             parameters: _tagHelperContext.HtmlEncoderPropertyName);
     }
 }
Example #36
0
        public void Visit_WithDesignTimeHost_GeneratesPropertiesAndLinePragmas_ForInjectChunks()
        {
            // Arrange
            var expected = string.Join(Environment.NewLine,
            @"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]",
            @"public",
            @"#line 1 """"",
            @"MyType1 MyPropertyName1",
            "",
            @"#line default",
            @"#line hidden",
            @"{ get; private set; }",
            @"[Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]",
            @"public",
            @"#line 1 """"",
            @"MyType2 @MyPropertyName2",
            "",
            @"#line default",
            @"#line hidden",
            @"{ get; private set; }",
            "");
            var writer = new CSharpCodeWriter();
            var context = CreateContext();
            context.Host.DesignTimeMode = true;

            var visitor = new InjectChunkVisitor(writer, context, "Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute");
            var factory = SpanFactory.CreateCsHtml();
            var node = (Span)factory.Code("Some code")
                                    .As(new InjectParameterGenerator("MyType", "MyPropertyName"));

            // Act
            visitor.Accept(new Chunk[]
            {
                new LiteralChunk(),
                new InjectChunk("MyType1", "MyPropertyName1") { Association = node },
                new InjectChunk("MyType2", "@MyPropertyName2") { Association = node }
            });
            var code = writer.GenerateCode();

            // Assert
            Assert.Equal(expected, code);
        }