Flow RootNamespace from MSBuild (dotnet/aspnetcore-tooling#331)

- Flow Root namespace through in command line builds

- Flow Root namespace through in design time builds

- Feedback\n\nCommit migrated from 057d4f3570
This commit is contained in:
Ajay Bhargav Baaskaran 2019-03-13 14:18:07 -07:00 committed by GitHub
parent eeabe9ee71
commit 2c39457306
16 changed files with 106 additions and 27 deletions

View File

@ -1,6 +1,6 @@
// <auto-generated/> // <auto-generated/>
#pragma warning disable 1591 #pragma warning disable 1591
namespace __BlazorGenerated namespace __GeneratedComponent
{ {
#line hidden #line hidden
using TModel = global::System.Object; using TModel = global::System.Object;

View File

@ -1,5 +1,5 @@
Document - Document -
NamespaceDeclaration - - __BlazorGenerated NamespaceDeclaration - - __GeneratedComponent
UsingDirective - - TModel = global::System.Object UsingDirective - - TModel = global::System.Object
UsingDirective - (1:0,1 [12] ) - System UsingDirective - (1:0,1 [12] ) - System
UsingDirective - (16:1,1 [32] ) - System.Collections.Generic UsingDirective - (16:1,1 [32] ) - System.Collections.Generic

View File

@ -1,23 +1,23 @@
Source Location: (12:0,12 [11] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) Source Location: (12:0,12 [11] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml)
|IDisposable| |IDisposable|
Generated Location: (662:17,0 [11] ) Generated Location: (665:17,0 [11] )
|IDisposable| |IDisposable|
Source Location: (38:1,13 [15] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) Source Location: (38:1,13 [15] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml)
|this.ToString()| |this.ToString()|
Generated Location: (1258:33,13 [15] ) Generated Location: (1261:33,13 [15] )
|this.ToString()| |this.ToString()|
Source Location: (79:3,5 [29] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) Source Location: (79:3,5 [29] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml)
|string.Format("{0}", "Hello")| |string.Format("{0}", "Hello")|
Generated Location: (1403:38,6 [29] ) Generated Location: (1406:38,6 [29] )
|string.Format("{0}", "Hello")| |string.Format("{0}", "Hello")|
Source Location: (132:6,12 [37] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml) Source Location: (132:6,12 [37] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml)
| |
void IDisposable.Dispose(){ } void IDisposable.Dispose(){ }
| |
Generated Location: (1617:45,12 [37] ) Generated Location: (1620:45,12 [37] )
| |
void IDisposable.Dispose(){ } void IDisposable.Dispose(){ }
| |

View File

@ -1,7 +1,7 @@
#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "d3c3d6059615673cb46fc4974164d61eabadb890" #pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/BasicComponent.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "d3c3d6059615673cb46fc4974164d61eabadb890"
// <auto-generated/> // <auto-generated/>
#pragma warning disable 1591 #pragma warning disable 1591
namespace __BlazorGenerated namespace __GeneratedComponent
{ {
#line hidden #line hidden
using System; using System;

View File

@ -1,5 +1,5 @@
Document - Document -
NamespaceDeclaration - - __BlazorGenerated NamespaceDeclaration - - __GeneratedComponent
UsingDirective - (1:0,1 [14] ) - System UsingDirective - (1:0,1 [14] ) - System
UsingDirective - (16:1,1 [34] ) - System.Collections.Generic UsingDirective - (16:1,1 [34] ) - System.Collections.Generic
UsingDirective - (51:2,1 [19] ) - System.Linq UsingDirective - (51:2,1 [19] ) - System.Linq

View File

@ -18,11 +18,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
private static readonly char[] NamespaceSeparators = new char[] { '.' }; private static readonly char[] NamespaceSeparators = new char[] { '.' };
/// <summary> /// <summary>
/// The base namespace. /// The fallback value of the root namespace. Only used if the fallback root namespace
/// was not passed in.
/// </summary> /// </summary>
// This is a fallback value and will only be used if we can't compute public string FallbackRootNamespace { get; set; } = "__GeneratedComponent";
// a reasonable namespace.
public string BaseNamespace { get; set; } = "__BlazorGenerated";
/// <summary> /// <summary>
/// Gets or sets whether to mangle class names. /// Gets or sets whether to mangle class names.
@ -58,7 +57,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
ClassDeclarationIntermediateNode @class, ClassDeclarationIntermediateNode @class,
MethodDeclarationIntermediateNode method) MethodDeclarationIntermediateNode method)
{ {
var options = codeDocument.GetDocumentIntermediateNode().Options;
if (!TryComputeNamespaceAndClass( if (!TryComputeNamespaceAndClass(
options,
codeDocument.Source.FilePath, codeDocument.Source.FilePath,
codeDocument.Source.RelativePath, codeDocument.Source.RelativePath,
out var computedNamespace, out var computedNamespace,
@ -66,7 +67,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
{ {
// If we can't compute a nice namespace (no relative path) then just generate something // If we can't compute a nice namespace (no relative path) then just generate something
// mangled. // mangled.
computedNamespace = BaseNamespace; computedNamespace = FallbackRootNamespace;
var checksum = Checksum.BytesToString(codeDocument.Source.GetChecksum()); var checksum = Checksum.BytesToString(codeDocument.Source.GetChecksum());
computedClass = $"AspNetCore_{checksum}"; computedClass = $"AspNetCore_{checksum}";
} }
@ -125,7 +126,12 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
// //
// However all kinds of thing are possible in tools. We shouldn't barf here if the document isn't // However all kinds of thing are possible in tools. We shouldn't barf here if the document isn't
// set up correctly. // set up correctly.
private bool TryComputeNamespaceAndClass(string filePath, string relativePath, out string @namespace, out string @class) private bool TryComputeNamespaceAndClass(
RazorCodeGenerationOptions options,
string filePath,
string relativePath,
out string @namespace,
out string @class)
{ {
if (filePath == null || relativePath == null || filePath.Length <= relativePath.Length) if (filePath == null || relativePath == null || filePath.Length <= relativePath.Length)
{ {
@ -134,14 +140,8 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
return false; return false;
} }
// Try and infer a namespace from the project directory. We don't yet have the ability to pass var rootNamespace = options.RootNamespace;
// the namespace through from the project. if (string.IsNullOrEmpty(rootNamespace))
var trimLength = relativePath.Length + (relativePath.StartsWith("/") ? 0 : 1);
var baseDirectory = filePath.Substring(0, filePath.Length - trimLength);
var lastSlash = baseDirectory.LastIndexOfAny(PathSeparators);
var baseNamespace = lastSlash == -1 ? baseDirectory : baseDirectory.Substring(lastSlash + 1);
if (string.IsNullOrEmpty(baseNamespace))
{ {
@namespace = null; @namespace = null;
@class = null; @class = null;
@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
var builder = new StringBuilder(); var builder = new StringBuilder();
// Sanitize the base namespace, but leave the dots. // Sanitize the base namespace, but leave the dots.
var segments = baseNamespace.Split(NamespaceSeparators, StringSplitOptions.RemoveEmptyEntries); var segments = rootNamespace.Split(NamespaceSeparators, StringSplitOptions.RemoveEmptyEntries);
builder.Append(CSharpIdentifier.SanitizeIdentifier(segments[0])); builder.Append(CSharpIdentifier.SanitizeIdentifier(segments[0]));
for (var i = 1; i < segments.Length; i++) for (var i = 1; i < segments.Length; i++)
{ {

View File

@ -8,7 +8,8 @@ namespace Microsoft.AspNetCore.Razor.Language
public DefaultRazorCodeGenerationOptions( public DefaultRazorCodeGenerationOptions(
bool indentWithTabs, bool indentWithTabs,
int indentSize, int indentSize,
bool designTime, bool designTime,
string rootNamespace,
bool suppressChecksum, bool suppressChecksum,
bool supressMetadataAttributes, bool supressMetadataAttributes,
bool suppressPrimaryMethodBody) bool suppressPrimaryMethodBody)
@ -16,6 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Language
IndentWithTabs = indentWithTabs; IndentWithTabs = indentWithTabs;
IndentSize = indentSize; IndentSize = indentSize;
DesignTime = designTime; DesignTime = designTime;
RootNamespace = rootNamespace;
SuppressChecksum = suppressChecksum; SuppressChecksum = suppressChecksum;
SuppressMetadataAttributes = supressMetadataAttributes; SuppressMetadataAttributes = supressMetadataAttributes;
SuppressPrimaryMethodBody = suppressPrimaryMethodBody; SuppressPrimaryMethodBody = suppressPrimaryMethodBody;
@ -27,6 +29,8 @@ namespace Microsoft.AspNetCore.Razor.Language
public override int IndentSize { get; } public override int IndentSize { get; }
public override string RootNamespace { get; }
public override bool SuppressChecksum { get; } public override bool SuppressChecksum { get; }
} }
} }

View File

@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.Razor.Language
IndentWithTabs, IndentWithTabs,
IndentSize, IndentSize,
DesignTime, DesignTime,
RootNamespace,
SuppressChecksum, SuppressChecksum,
SuppressMetadataAttributes, SuppressMetadataAttributes,
SuppressPrimaryMethodBody); SuppressPrimaryMethodBody);

View File

@ -14,6 +14,7 @@ namespace Microsoft.AspNetCore.Razor.Language
indentSize: 4, indentSize: 4,
designTime: false, designTime: false,
suppressChecksum: false, suppressChecksum: false,
rootNamespace: null,
supressMetadataAttributes: false, supressMetadataAttributes: false,
suppressPrimaryMethodBody: false); suppressPrimaryMethodBody: false);
} }
@ -24,6 +25,7 @@ namespace Microsoft.AspNetCore.Razor.Language
indentWithTabs: false, indentWithTabs: false,
indentSize: 4, indentSize: 4,
designTime: true, designTime: true,
rootNamespace: null,
suppressChecksum: false, suppressChecksum: false,
supressMetadataAttributes: true, supressMetadataAttributes: true,
suppressPrimaryMethodBody: false); suppressPrimaryMethodBody: false);
@ -67,6 +69,11 @@ namespace Microsoft.AspNetCore.Razor.Language
public abstract int IndentSize { get; } public abstract int IndentSize { get; }
/// <summary>
/// Gets the root namespace for the generated code.
/// </summary>
public virtual string RootNamespace { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether to suppress the default <c>#pragma checksum</c> directive in the /// Gets a value that indicates whether to suppress the default <c>#pragma checksum</c> directive in the
/// generated C# code. If <c>false</c> the checkum directive will be included, otherwise it will not be /// generated C# code. If <c>false</c> the checkum directive will be included, otherwise it will not be

View File

@ -15,6 +15,11 @@ namespace Microsoft.AspNetCore.Razor.Language
public abstract bool IndentWithTabs { get; set; } public abstract bool IndentWithTabs { get; set; }
/// <summary>
/// Gets or sets the root namespace of the generated code.
/// </summary>
public virtual string RootNamespace { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value that indicates whether to suppress the default <c>#pragma checksum</c> directive in the /// Gets or sets a value that indicates whether to suppress the default <c>#pragma checksum</c> directive in the
/// generated C# code. If <c>false</c> the checkum directive will be included, otherwise it will not be /// generated C# code. If <c>false</c> the checkum directive will be included, otherwise it will not be

View File

@ -75,6 +75,23 @@ namespace Microsoft.AspNetCore.Razor.Language
return builder; return builder;
} }
/// <summary>
/// Sets the root namespace for the generated code.
/// </summary>
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
/// <param name="rootNamespace">The root namespace.</param>
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
public static RazorProjectEngineBuilder SetRootNamespace(this RazorProjectEngineBuilder builder, string rootNamespace)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Features.Add(new ConfigureRootNamespaceFeature(rootNamespace));
return builder;
}
public static void SetImportFeature(this RazorProjectEngineBuilder builder, IImportProjectFeature feature) public static void SetImportFeature(this RazorProjectEngineBuilder builder, IImportProjectFeature feature)
{ {
if (builder == null) if (builder == null)
@ -281,5 +298,29 @@ namespace Microsoft.AspNetCore.Razor.Language
public override Stream Read() => new MemoryStream(_importBytes); public override Stream Read() => new MemoryStream(_importBytes);
} }
} }
private class ConfigureRootNamespaceFeature : IConfigureRazorCodeGenerationOptionsFeature
{
private readonly string _rootNamespace;
public ConfigureRootNamespaceFeature(string rootNamespace)
{
_rootNamespace = rootNamespace;
}
public int Order { get; set; }
public RazorEngine Engine { get; set; }
public void Configure(RazorCodeGenerationOptionsBuilder options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
options.RootNamespace = _rootNamespace;
}
}
} }
} }

View File

@ -29,6 +29,7 @@ namespace Microsoft.AspNetCore.Razor.Tools
Configuration = Option("-c", "Razor configuration name", CommandOptionType.SingleValue); Configuration = Option("-c", "Razor configuration name", CommandOptionType.SingleValue);
ExtensionNames = Option("-n", "extension name", CommandOptionType.MultipleValue); ExtensionNames = Option("-n", "extension name", CommandOptionType.MultipleValue);
ExtensionFilePaths = Option("-e", "extension file path", CommandOptionType.MultipleValue); ExtensionFilePaths = Option("-e", "extension file path", CommandOptionType.MultipleValue);
RootNamespace = Option("--root-namespace", "root namespace for generated code", CommandOptionType.SingleValue);
GenerateDeclaration = Option("--generate-declaration", "Generate declaration", CommandOptionType.NoValue); GenerateDeclaration = Option("--generate-declaration", "Generate declaration", CommandOptionType.NoValue);
} }
@ -52,6 +53,8 @@ namespace Microsoft.AspNetCore.Razor.Tools
public CommandOption ExtensionFilePaths { get; } public CommandOption ExtensionFilePaths { get; }
public CommandOption RootNamespace { get; }
public CommandOption GenerateDeclaration { get; } public CommandOption GenerateDeclaration { get; }
protected override Task<int> ExecuteCoreAsync() protected override Task<int> ExecuteCoreAsync()
@ -176,6 +179,11 @@ namespace Microsoft.AspNetCore.Razor.Tools
{ {
b.Features.Add(new SetSuppressPrimaryMethodBodyOptionFeature()); b.Features.Add(new SetSuppressPrimaryMethodBodyOptionFeature());
} }
if (RootNamespace.HasValue())
{
b.SetRootNamespace(RootNamespace.Value());
}
}); });
var results = GenerateCode(engine, sourceItems); var results = GenerateCode(engine, sourceItems);

View File

@ -24,6 +24,8 @@ namespace Microsoft.AspNetCore.Razor.Tasks
private const string AssemblyName = "AssemblyName"; private const string AssemblyName = "AssemblyName";
private const string AssemblyFilePath = "AssemblyFilePath"; private const string AssemblyFilePath = "AssemblyFilePath";
public string RootNamespace { get; set; }
[Required] [Required]
public string Version { get; set; } public string Version { get; set; }
@ -135,6 +137,13 @@ namespace Microsoft.AspNetCore.Razor.Tasks
builder.AppendLine("-c"); builder.AppendLine("-c");
builder.AppendLine(Configuration[0].GetMetadata(Identity)); builder.AppendLine(Configuration[0].GetMetadata(Identity));
// Added in 3.0
if (parsedVersion.Major >= 3 && !string.IsNullOrEmpty(RootNamespace))
{
builder.AppendLine("--root-namespace");
builder.AppendLine(RootNamespace);
}
// Added in 3.0 // Added in 3.0
if (parsedVersion.Major >= 3 && GenerateDeclaration) if (parsedVersion.Major >= 3 && GenerateDeclaration)
{ {

View File

@ -155,6 +155,7 @@ Copyright (c) .NET Foundation. All rights reserved.
ForceServer="$(_RazorForceBuildServer)" ForceServer="$(_RazorForceBuildServer)"
PipeName="$(_RazorBuildServerPipeName)" PipeName="$(_RazorBuildServerPipeName)"
Version="$(RazorLangVersion)" Version="$(RazorLangVersion)"
RootNamespace="$(RootNamespace)"
Configuration="@(ResolvedRazorConfiguration)" Configuration="@(ResolvedRazorConfiguration)"
Extensions="@(ResolvedRazorExtension)" Extensions="@(ResolvedRazorExtension)"
Sources="@(RazorGenerateWithTargetPath)" Sources="@(RazorGenerateWithTargetPath)"

View File

@ -98,6 +98,7 @@ Copyright (c) .NET Foundation. All rights reserved.
ForceServer="$(_RazorForceBuildServer)" ForceServer="$(_RazorForceBuildServer)"
PipeName="$(_RazorBuildServerPipeName)" PipeName="$(_RazorBuildServerPipeName)"
Version="$(RazorLangVersion)" Version="$(RazorLangVersion)"
RootNamespace="$(RootNamespace)"
Configuration="@(ResolvedRazorConfiguration)" Configuration="@(ResolvedRazorConfiguration)"
Extensions="@(ResolvedRazorExtension)" Extensions="@(ResolvedRazorExtension)"
Sources="@(_RazorComponentDeclarationSources)" Sources="@(_RazorComponentDeclarationSources)"

View File

@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
PathSeparator = Path.DirectorySeparatorChar.ToString(); PathSeparator = Path.DirectorySeparatorChar.ToString();
WorkingDirectory = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ArbitraryWindowsPath : ArbitraryMacLinuxPath; WorkingDirectory = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ArbitraryWindowsPath : ArbitraryMacLinuxPath;
DefaultBaseNamespace = "Test"; // Matches the default working directory DefaultRootNamespace = "Test"; // Matches the default working directory
DefaultFileName = "TestComponent.cshtml"; DefaultFileName = "TestComponent.cshtml";
} }
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
internal virtual RazorConfiguration Configuration { get; } internal virtual RazorConfiguration Configuration { get; }
internal virtual string DefaultBaseNamespace { get; } internal virtual string DefaultRootNamespace { get; }
internal virtual string DefaultFileName { get; } internal virtual string DefaultFileName { get; }
@ -113,6 +113,8 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
{ {
return RazorProjectEngine.Create(configuration, FileSystem, b => return RazorProjectEngine.Create(configuration, FileSystem, b =>
{ {
b.SetRootNamespace(DefaultRootNamespace);
// Turn off checksums, we're testing code generation. // Turn off checksums, we're testing code generation.
b.Features.Add(new SuppressChecksum()); b.Features.Add(new SuppressChecksum());
@ -320,7 +322,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
{ {
var assemblyResult = CompileToAssembly(DefaultFileName, cshtmlSource); var assemblyResult = CompileToAssembly(DefaultFileName, cshtmlSource);
var componentFullTypeName = $"{DefaultBaseNamespace}.{Path.GetFileNameWithoutExtension(DefaultFileName)}"; var componentFullTypeName = $"{DefaultRootNamespace}.{Path.GetFileNameWithoutExtension(DefaultFileName)}";
return CompileToComponent(assemblyResult, componentFullTypeName); return CompileToComponent(assemblyResult, componentFullTypeName);
} }