-
Notifications
You must be signed in to change notification settings - Fork 224
Added view component tag helper updates. #823
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ public CSharpCodeGenerator(CodeGeneratorContext context) | |
{ | ||
} | ||
|
||
private ChunkTree Tree { get { return Context.ChunkTreeBuilder.Root; } } | ||
protected ChunkTree Tree { get { return Context.ChunkTreeBuilder.Root; } } | ||
public RazorEngineHost Host { get { return Context.Host; } } | ||
|
||
/// <summary> | ||
|
@@ -82,12 +82,23 @@ public override CodeGeneratorResult Generate() | |
csharpCodeVisitor.Accept(Tree.Children); | ||
} | ||
} | ||
|
||
BuildAfterExecuteContent(writer, Tree.Children); | ||
} | ||
} | ||
|
||
return new CodeGeneratorResult(writer.GenerateCode(), writer.LineMappingManager.Mappings); | ||
} | ||
|
||
/// <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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgot: Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Decided offline to leave this as is b/c |
||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if you mutate the chunks list here (add/remove)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean that we would For view component tag helpers, we need to mutate their chunks such that the type name includes the name of the page (ex. This needs to be done before the logic in lines 68-71, since that's when the type names of the chunks are written in the generated code. We could actually call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both here and in Similarly, what happens if chunks are removed. Will code that runs later blow up? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, understood. I don't think anything would blow up... It would be similar to adding/deleting parts of the .cshtml file, maybe. Worst case, you could change the content of the chunks and rewrite the view? If the chunks were invalid, perhaps things would just not render? (I'm not sure on this, what do you think?) The chunk list has to be modifiable in our current implementation so we can modify the type names. Is this valid? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, |
||
} | ||
|
||
protected virtual CSharpCodeVisitor CreateCSharpCodeVisitor( | ||
CSharpCodeWriter writer, | ||
CodeGeneratorContext context) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -319,6 +319,17 @@ public CSharpCodeWriter WriteMethodInvocation(string methodName, bool endLine, p | |
.WriteEndMethodInvocation(endLine); | ||
} | ||
|
||
public CSharpCodeWriter WriteAutoPropertyDeclaration(string accessibility, string typeName, string name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume the view component as tag helper feature needs easy auto-property generation. Correct? But why does this method need to exist in Razor? MVC or any external code could implement this as an extension method: public static CSharpCodeWriter WriteAutoPropertyDeclaration(
this CSharpCodeWriter writer,
string accessibility,
string typeName,
string name)
{
return writer
.Write(accessibility)
// ...
.WriteLine();
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. Do you recommend taking this out? We could maybe start a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's generic enough to leave in the base. Are there other similar methods? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussed offline. This is fine as-is. |
||
{ | ||
return Write(accessibility) | ||
.Write(" ") | ||
.Write(typeName) | ||
.Write(" ") | ||
.Write(name) | ||
.Write(" { get; set; }") | ||
.WriteLine(); | ||
} | ||
|
||
public CSharpDisableWarningScope BuildDisableWarningScope(int warning) | ||
{ | ||
return new CSharpDisableWarningScope(this, warning); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,10 @@ | |
#if GENERATE_BASELINES | ||
using System; | ||
#endif | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.AspNetCore.Razor.Chunks; | ||
using Microsoft.AspNetCore.Razor.Chunks.Generators; | ||
using Microsoft.AspNetCore.Razor.Parser.SyntaxTree; | ||
using Microsoft.AspNetCore.Razor.Test.CodeGenerators; | ||
using Microsoft.AspNetCore.Razor.Test.Utils; | ||
|
@@ -14,9 +18,15 @@ namespace Microsoft.AspNetCore.Razor.CodeGenerators | |
{ | ||
public class CSharpCodeGeneratorTest | ||
{ | ||
#if GENERATE_BASELINES | ||
private static readonly string _baselinePathStart = "test/Microsoft.AspNetCore.Razor.Test"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the field is |
||
#endif | ||
private static readonly string _testOutputDirectory = "TestFiles/CodeGenerator/Output/CSharpCodeGenerator"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Discussed offline. This is actually used to find resources and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But do we want the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On second thought, leave the final folder there. Just make sure the files are written correctly w/ |
||
|
||
[Fact] | ||
public void ChunkTreeWithUsings() | ||
{ | ||
// Arrange | ||
var syntaxTreeNode = new Mock<Span>(new SpanBuilder()); | ||
var language = new CSharpRazorCodeLanguage(); | ||
var host = new CodeGenTestHost(language); | ||
|
@@ -30,7 +40,9 @@ public void ChunkTreeWithUsings() | |
codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object); | ||
codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object); | ||
var codeGenerator = new CodeGenTestCodeGenerator(codeGeneratorContext); | ||
var testFile = TestFile.Create("TestFiles/CodeGenerator/Output/CSharpCodeGenerator.cs"); | ||
|
||
var path = $"{_testOutputDirectory}/ChunkTreeWithUsings.cs"; | ||
var testFile = TestFile.Create(path); | ||
|
||
string expectedOutput; | ||
#if GENERATE_BASELINES | ||
|
@@ -54,14 +66,151 @@ public void ChunkTreeWithUsings() | |
// Update baseline files if files do not already match. | ||
if (!string.Equals(expectedOutput, result.Code, StringComparison.Ordinal)) | ||
{ | ||
BaselineWriter.WriteBaseline( | ||
@"test\Microsoft.AspNetCore.Razor.Test\TestFiles\CodeGenerator\Output\CSharpCodeGenerator.cs", | ||
result.Code); | ||
var baselinePath = $"{_baselinePathStart}/{_testOutputDirectory}/ChunkTreeWithUsings.cs"; | ||
BaselineWriter.WriteBaseline( baselinePath, result.Code); | ||
} | ||
#else | ||
Assert.Equal(expectedOutput, result.Code); | ||
#endif | ||
} | ||
} | ||
} | ||
|
||
public static TheoryData ModifyOutputData | ||
{ | ||
get | ||
{ | ||
var addFileName = "AddGenerateChunkTest.cs"; | ||
var addGenerator = new AddGenerateTestCodeGenerator(CreateContext()); | ||
var addResult = CreateCodeGeneratorResult(addFileName); | ||
|
||
var clearFileName = "ClearGenerateChunkTest.cs"; | ||
var clearGenerator = new ClearGenerateTestCodeGenerator(CreateContext()); | ||
var clearResult = CreateCodeGeneratorResult(clearFileName); | ||
|
||
var defaultFileName = "DefaultGenerateChunkTest.cs"; | ||
var defaultGenerator = new CSharpCodeGenerator(CreateContext()); | ||
var defaultResult = CreateCodeGeneratorResult(defaultFileName); | ||
|
||
var commentFileName = "BuildAfterExecuteContentTest.cs"; | ||
var commentGenerator = new BuildAfterExecuteContentTestCodeGenerator(CreateContext()); | ||
var commentResult = CreateCodeGeneratorResult(commentFileName); | ||
|
||
return new TheoryData<CSharpCodeGenerator, CodeGeneratorResult, string> | ||
{ | ||
{addGenerator, addResult, addFileName}, | ||
{clearGenerator, clearResult, clearFileName }, | ||
{defaultGenerator, defaultResult, defaultFileName }, | ||
{commentGenerator, commentResult, commentFileName } | ||
}; | ||
} | ||
} | ||
|
||
[Theory] | ||
[MemberData(nameof(ModifyOutputData))] | ||
public void BuildAfterExecuteContent_ModifyChunks_ModifyOutput( | ||
CSharpCodeGenerator generator, | ||
CodeGeneratorResult expectedResult, | ||
string fileName) | ||
{ | ||
// Arrange, Act | ||
var result = generator.Generate(); | ||
|
||
// Assert | ||
#if GENERATE_BASELINES | ||
// Update baseline files if files do not already match. | ||
if (!string.Equals(expectedResult.Code, result.Code, StringComparison.Ordinal)) | ||
{ | ||
var baselinePath = $"{_baselinePathStart}/{_testOutputDirectory}/{fileName}"; | ||
BaselineWriter.WriteBaseline( baselinePath, result.Code); | ||
} | ||
#else | ||
Assert.Equal(result.Code, expectedResult.Code); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do the |
||
#endif | ||
} | ||
|
||
|
||
private static CodeGeneratorResult CreateCodeGeneratorResult(string fileName) | ||
{ | ||
var path = $"{_testOutputDirectory}/{fileName}"; | ||
var file = TestFile.Create(path); | ||
string code; | ||
|
||
#if GENERATE_BASELINES | ||
if (file.Exists()) | ||
{ | ||
code = file.ReadAllText(); | ||
} | ||
else | ||
{ | ||
code = null; | ||
} | ||
#else | ||
code = file.ReadAllText(); | ||
#endif | ||
|
||
var result = new CodeGeneratorResult(code, new List<LineMapping>()); | ||
return result; | ||
} | ||
|
||
// Returns a context with two literal chunks. | ||
private static CodeGeneratorContext CreateContext() | ||
{ | ||
var language = new CSharpRazorCodeLanguage(); | ||
var host = new CodeGenTestHost(language); | ||
|
||
var codeGeneratorContext = new CodeGeneratorContext( | ||
new ChunkGeneratorContext( | ||
host, | ||
host.DefaultClassName, | ||
host.DefaultNamespace, | ||
"", | ||
shouldGenerateLinePragmas: false), | ||
new ErrorSink()); | ||
|
||
codeGeneratorContext.ChunkTreeBuilder = new ChunkTreeBuilder(); | ||
var syntaxTreeNode = new Mock<Span>(new SpanBuilder()); | ||
codeGeneratorContext.ChunkTreeBuilder.AddLiteralChunk("hello", syntaxTreeNode.Object); | ||
codeGeneratorContext.ChunkTreeBuilder.AddStatementChunk("// asdf", syntaxTreeNode.Object); | ||
codeGeneratorContext.ChunkTreeBuilder.AddLiteralChunk("world", syntaxTreeNode.Object); | ||
return codeGeneratorContext; | ||
} | ||
|
||
private class BuildAfterExecuteContentTestCodeGenerator : CSharpCodeGenerator | ||
{ | ||
public BuildAfterExecuteContentTestCodeGenerator(CodeGeneratorContext context) : base(context) | ||
{ | ||
} | ||
|
||
protected override void BuildAfterExecuteContent(CSharpCodeWriter writer, IList<Chunk> chunks) | ||
{ | ||
writer.WriteLine("// test add content."); | ||
} | ||
} | ||
|
||
private class AddGenerateTestCodeGenerator : CSharpCodeGenerator | ||
{ | ||
public AddGenerateTestCodeGenerator(CodeGeneratorContext context) : base(context) | ||
{ | ||
} | ||
|
||
public override CodeGeneratorResult Generate() | ||
{ | ||
var firstChunk = Tree.Children.First(); | ||
Tree.Children.Add(firstChunk); | ||
return base.Generate(); | ||
} | ||
} | ||
|
||
private class ClearGenerateTestCodeGenerator : CSharpCodeGenerator | ||
{ | ||
public ClearGenerateTestCodeGenerator(CodeGeneratorContext context) : base(context) | ||
{ | ||
} | ||
|
||
public override CodeGeneratorResult Generate() | ||
{ | ||
Tree.Children.Clear(); | ||
return base.Generate(); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
namespace Razor | ||
{ | ||
using System.Threading.Tasks; | ||
|
||
public class __CompiledTemplate | ||
{ | ||
#line hidden | ||
public __CompiledTemplate() | ||
{ | ||
} | ||
|
||
#pragma warning disable 1998 | ||
public override async Task ExecuteAsync() | ||
{ | ||
WriteLiteral("hello"); | ||
#line 1 "" | ||
// asdf | ||
|
||
#line default | ||
#line hidden | ||
|
||
WriteLiteral("world"); | ||
WriteLiteral("hello"); | ||
} | ||
#pragma warning restore 1998 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
namespace Razor | ||
{ | ||
using System.Threading.Tasks; | ||
|
||
public class __CompiledTemplate | ||
{ | ||
#line hidden | ||
public __CompiledTemplate() | ||
{ | ||
} | ||
|
||
#pragma warning disable 1998 | ||
public override async Task ExecuteAsync() | ||
{ | ||
WriteLiteral("hello"); | ||
#line 1 "" | ||
// asdf | ||
|
||
#line default | ||
#line hidden | ||
|
||
WriteLiteral("world"); | ||
} | ||
#pragma warning restore 1998 | ||
// test add content. | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Razor | ||
{ | ||
using System.Threading.Tasks; | ||
|
||
public class __CompiledTemplate | ||
{ | ||
#line hidden | ||
public __CompiledTemplate() | ||
{ | ||
} | ||
|
||
#pragma warning disable 1998 | ||
public override async Task ExecuteAsync() | ||
{ | ||
} | ||
#pragma warning restore 1998 | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to fix the
<example>
since this is nowpublic
. Right now all the lines will be shown as one messy line. Easiest to surround the lines w/<code>...</code>
.