140 lines
5.4 KiB
C#
140 lines
5.4 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNet.Razor.Chunks;
|
|
using Microsoft.AspNet.Razor.CodeGeneration.Visitors;
|
|
using Microsoft.Framework.Internal;
|
|
|
|
namespace Microsoft.AspNet.Razor.CodeGeneration
|
|
{
|
|
public class CSharpCodeBuilder : CodeBuilder
|
|
{
|
|
// See http://msdn.microsoft.com/en-us/library/system.codedom.codechecksumpragma.checksumalgorithmid.aspx
|
|
private const string Sha1AlgorithmId = "{ff1816ec-aa5e-4d10-87f7-6f4963833460}";
|
|
private const int DisableAsyncWarning = 1998;
|
|
|
|
public CSharpCodeBuilder(CodeBuilderContext context)
|
|
: base(context)
|
|
{
|
|
}
|
|
|
|
private ChunkTree Tree { get { return Context.ChunkTreeBuilder.ChunkTree; } }
|
|
public RazorEngineHost Host { get { return Context.Host; } }
|
|
|
|
// Internal for testing
|
|
internal virtual CSharpCodeWriter CreateCodeWriter()
|
|
{
|
|
return new CSharpCodeWriter();
|
|
}
|
|
|
|
public override CodeBuilderResult Build()
|
|
{
|
|
var writer = CreateCodeWriter();
|
|
|
|
if (!Host.DesignTimeMode && !string.IsNullOrEmpty(Context.Checksum))
|
|
{
|
|
writer.Write("#pragma checksum \"")
|
|
.Write(Context.SourceFile)
|
|
.Write("\" \"")
|
|
.Write(Sha1AlgorithmId)
|
|
.Write("\" \"")
|
|
.Write(Context.Checksum)
|
|
.WriteLine("\"");
|
|
}
|
|
|
|
using (writer.BuildNamespace(Context.RootNamespace))
|
|
{
|
|
// Write out using directives
|
|
AddImports(Tree, writer, Host.NamespaceImports);
|
|
// Separate the usings and the class
|
|
writer.WriteLine();
|
|
|
|
using (BuildClassDeclaration(writer))
|
|
{
|
|
if (Host.DesignTimeMode)
|
|
{
|
|
writer.WriteLine("private static object @__o;");
|
|
}
|
|
|
|
var csharpCodeVisitor = CreateCSharpCodeVisitor(writer, Context);
|
|
|
|
new CSharpTypeMemberVisitor(csharpCodeVisitor, writer, Context).Accept(Tree.Chunks);
|
|
new CSharpDesignTimeHelpersVisitor(csharpCodeVisitor, writer, Context).AcceptTree(Tree);
|
|
new CSharpTagHelperFieldDeclarationVisitor(writer, Context).Accept(Tree.Chunks);
|
|
|
|
BuildConstructor(writer);
|
|
|
|
// Add space in-between constructor and method body
|
|
writer.WriteLine();
|
|
|
|
using (writer.BuildDisableWarningScope(DisableAsyncWarning))
|
|
{
|
|
using (writer.BuildMethodDeclaration("public override async", "Task", Host.GeneratedClassContext.ExecuteMethodName))
|
|
{
|
|
new CSharpTagHelperRunnerInitializationVisitor(writer, Context).Accept(Tree.Chunks);
|
|
csharpCodeVisitor.Accept(Tree.Chunks);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return new CodeBuilderResult(writer.GenerateCode(), writer.LineMappingManager.Mappings);
|
|
}
|
|
|
|
protected virtual CSharpCodeVisitor CreateCSharpCodeVisitor([NotNull] CSharpCodeWriter writer,
|
|
[NotNull] CodeBuilderContext context)
|
|
{
|
|
return new CSharpCodeVisitor(writer, context);
|
|
}
|
|
|
|
protected virtual CSharpCodeWritingScope BuildClassDeclaration(CSharpCodeWriter writer)
|
|
{
|
|
var baseTypeVisitor = new CSharpBaseTypeVisitor(writer, Context);
|
|
baseTypeVisitor.Accept(Tree.Chunks);
|
|
|
|
var baseType = baseTypeVisitor.CurrentBaseType ?? Host.DefaultBaseClass;
|
|
|
|
var baseTypes = string.IsNullOrEmpty(baseType) ? Enumerable.Empty<string>() : new string[] { baseType };
|
|
|
|
return writer.BuildClassDeclaration("public", Context.ClassName, baseTypes);
|
|
}
|
|
|
|
protected virtual void BuildConstructor(CSharpCodeWriter writer)
|
|
{
|
|
writer.WriteLineHiddenDirective();
|
|
using (writer.BuildConstructor(Context.ClassName))
|
|
{
|
|
// Any constructor based logic that we need to add?
|
|
};
|
|
}
|
|
|
|
private void AddImports(ChunkTree chunkTree, CSharpCodeWriter writer, IEnumerable<string> defaultImports)
|
|
{
|
|
// Write out using directives
|
|
var usingVisitor = new CSharpUsingVisitor(writer, Context);
|
|
foreach (Chunk chunk in Tree.Chunks)
|
|
{
|
|
usingVisitor.Accept(chunk);
|
|
}
|
|
|
|
defaultImports = defaultImports.Except(usingVisitor.ImportedUsings);
|
|
|
|
foreach (string import in defaultImports)
|
|
{
|
|
writer.WriteUsing(import);
|
|
}
|
|
|
|
var taskNamespace = typeof(Task).Namespace;
|
|
|
|
// We need to add the task namespace but ONLY if it hasn't been added by the default imports or using imports yet.
|
|
if (!defaultImports.Contains(taskNamespace) && !usingVisitor.ImportedUsings.Contains(taskNamespace))
|
|
{
|
|
writer.WriteUsing(taskNamespace);
|
|
}
|
|
}
|
|
}
|
|
}
|