Better support for _Imports.razor (dotnet/aspnetcore-tooling#357)
* Better support for _Imports.razor
* Special case component imports when generating code
* Prevent a future VS crash
* Rebased and updated
* update
* Removed unnecessary newline
\n\nCommit migrated from abbfe00bdc
This commit is contained in:
parent
784596aba6
commit
730f3cdc6b
|
|
@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Razor.Language {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file.
|
/// Looks up a localized string similar to The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string PageDirectiveCannotBeImported {
|
internal static string PageDirectiveCannotBeImported {
|
||||||
get {
|
get {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@
|
||||||
<value>TypeName</value>
|
<value>TypeName</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PageDirectiveCannotBeImported" xml:space="preserve">
|
<data name="PageDirectiveCannotBeImported" xml:space="preserve">
|
||||||
<value>The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor cshtml file</value>
|
<value>The '@{0}' directive specified in {1} file will not be imported. The directive must appear at the top of each Razor file</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PageDirective_Description" xml:space="preserve">
|
<data name="PageDirective_Description" xml:space="preserve">
|
||||||
<value>Mark the page as a routable component.</value>
|
<value>Mark the page as a routable component.</value>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
public static readonly RazorDiagnosticDescriptor UnsupportedTagHelperDirective = new RazorDiagnosticDescriptor(
|
public static readonly RazorDiagnosticDescriptor UnsupportedTagHelperDirective = new RazorDiagnosticDescriptor(
|
||||||
$"{DiagnosticPrefix}9978",
|
$"{DiagnosticPrefix}9978",
|
||||||
() =>
|
() =>
|
||||||
"The directives @addTagHelper, @removeTagHelper and @tagHelperPrefix are not valid in a component document." +
|
"The directives @addTagHelper, @removeTagHelper and @tagHelperPrefix are not valid in a component document. " +
|
||||||
"Use '@using <namespace>' directive instead.",
|
"Use '@using <namespace>' directive instead.",
|
||||||
RazorDiagnosticSeverity.Error);
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
|
|
@ -321,5 +321,16 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
{
|
{
|
||||||
return RazorDiagnostic.Create(ChildContentHasInvalidParameterOnComponent, source ?? SourceSpan.Undefined, attribute, element);
|
return RazorDiagnostic.Create(ChildContentHasInvalidParameterOnComponent, source ?? SourceSpan.Undefined, attribute, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly RazorDiagnosticDescriptor UnsupportedComponentImportContent =
|
||||||
|
new RazorDiagnosticDescriptor(
|
||||||
|
$"{DiagnosticPrefix}10003",
|
||||||
|
() => "Markup, code and block directives are not valid in component imports.",
|
||||||
|
RazorDiagnosticSeverity.Error);
|
||||||
|
|
||||||
|
public static RazorDiagnostic Create_UnsupportedComponentImportContent(SourceSpan? source)
|
||||||
|
{
|
||||||
|
return RazorDiagnostic.Create(UnsupportedComponentImportContent, source ?? SourceSpan.Undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,47 +70,63 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
}
|
}
|
||||||
|
|
||||||
@namespace.Content = computedNamespace;
|
@namespace.Content = computedNamespace;
|
||||||
|
|
||||||
@class.BaseType = ComponentsApi.ComponentBase.FullTypeName;
|
|
||||||
@class.ClassName = computedClass;
|
@class.ClassName = computedClass;
|
||||||
@class.Modifiers.Clear();
|
@class.Modifiers.Clear();
|
||||||
@class.Modifiers.Add("public");
|
@class.Modifiers.Add("public");
|
||||||
|
|
||||||
var documentNode = codeDocument.GetDocumentIntermediateNode();
|
if (FileKinds.IsComponentImport(codeDocument.GetFileKind()))
|
||||||
var typeParamReferences = documentNode.FindDirectiveReferences(ComponentTypeParamDirective.Directive);
|
|
||||||
for (var i = 0; i < typeParamReferences.Count; i++)
|
|
||||||
{
|
{
|
||||||
var typeParamNode = (DirectiveIntermediateNode)typeParamReferences[i].Node;
|
// We don't want component imports to be considered as real component.
|
||||||
if (typeParamNode.HasDiagnostics)
|
// But we still want to generate code for it so we can get diagnostics.
|
||||||
|
@class.BaseType = typeof(object).FullName;
|
||||||
|
|
||||||
|
method.ReturnType = "void";
|
||||||
|
method.MethodName = "Execute";
|
||||||
|
method.Modifiers.Clear();
|
||||||
|
method.Modifiers.Add("protected");
|
||||||
|
|
||||||
|
method.Parameters.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@class.BaseType = ComponentsApi.ComponentBase.FullTypeName;
|
||||||
|
|
||||||
|
var documentNode = codeDocument.GetDocumentIntermediateNode();
|
||||||
|
var typeParamReferences = documentNode.FindDirectiveReferences(ComponentTypeParamDirective.Directive);
|
||||||
|
for (var i = 0; i < typeParamReferences.Count; i++)
|
||||||
{
|
{
|
||||||
continue;
|
var typeParamNode = (DirectiveIntermediateNode)typeParamReferences[i].Node;
|
||||||
|
if (typeParamNode.HasDiagnostics)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@class.TypeParameters.Add(new TypeParameter() { ParameterName = typeParamNode.Tokens.First().Content, });
|
||||||
}
|
}
|
||||||
|
|
||||||
@class.TypeParameters.Add(new TypeParameter() { ParameterName = typeParamNode.Tokens.First().Content, });
|
method.ReturnType = "void";
|
||||||
|
method.MethodName = ComponentsApi.ComponentBase.BuildRenderTree;
|
||||||
|
method.Modifiers.Clear();
|
||||||
|
method.Modifiers.Add("protected");
|
||||||
|
method.Modifiers.Add("override");
|
||||||
|
|
||||||
|
method.Parameters.Clear();
|
||||||
|
method.Parameters.Add(new MethodParameter()
|
||||||
|
{
|
||||||
|
ParameterName = "builder",
|
||||||
|
TypeName = ComponentsApi.RenderTreeBuilder.FullTypeName,
|
||||||
|
});
|
||||||
|
|
||||||
|
// We need to call the 'base' method as the first statement.
|
||||||
|
var callBase = new CSharpCodeIntermediateNode();
|
||||||
|
callBase.Annotations.Add(BuildRenderTreeBaseCallAnnotation, true);
|
||||||
|
callBase.Children.Add(new IntermediateToken
|
||||||
|
{
|
||||||
|
Kind = TokenKind.CSharp,
|
||||||
|
Content = $"base.{ComponentsApi.ComponentBase.BuildRenderTree}(builder);"
|
||||||
|
});
|
||||||
|
method.Children.Insert(0, callBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
method.ReturnType = "void";
|
|
||||||
method.MethodName = ComponentsApi.ComponentBase.BuildRenderTree;
|
|
||||||
method.Modifiers.Clear();
|
|
||||||
method.Modifiers.Add("protected");
|
|
||||||
method.Modifiers.Add("override");
|
|
||||||
|
|
||||||
method.Parameters.Clear();
|
|
||||||
method.Parameters.Add(new MethodParameter()
|
|
||||||
{
|
|
||||||
ParameterName = "builder",
|
|
||||||
TypeName = ComponentsApi.RenderTreeBuilder.FullTypeName,
|
|
||||||
});
|
|
||||||
|
|
||||||
// We need to call the 'base' method as the first statement.
|
|
||||||
var callBase = new CSharpCodeIntermediateNode();
|
|
||||||
callBase.Annotations.Add(BuildRenderTreeBaseCallAnnotation, true);
|
|
||||||
callBase.Children.Add(new IntermediateToken
|
|
||||||
{
|
|
||||||
Kind = TokenKind.CSharp,
|
|
||||||
Content = $"base.{ComponentsApi.ComponentBase.BuildRenderTree}(builder);"
|
|
||||||
});
|
|
||||||
method.Children.Insert(0, callBase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsBuildRenderTreeBaseCall(CSharpCodeIntermediateNode node)
|
internal static bool IsBuildRenderTreeBaseCall(CSharpCodeIntermediateNode node)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(FileKinds.Component, Directive);
|
builder.AddDirective(Directive, FileKinds.Component, FileKinds.ComponentImport);
|
||||||
builder.Features.Add(new ComponentInjectDirectivePass());
|
builder.Features.Add(new ComponentInjectDirectivePass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(FileKinds.Component, Directive);
|
builder.AddDirective(Directive, FileKinds.Component, FileKinds.ComponentImport);
|
||||||
builder.Features.Add(new ComponentLayoutDirectivePass());
|
builder.Features.Add(new ComponentLayoutDirectivePass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
attributeNode.Children.Add(new IntermediateToken()
|
attributeNode.Children.Add(new IntermediateToken()
|
||||||
{
|
{
|
||||||
Kind = TokenKind.CSharp,
|
Kind = TokenKind.CSharp,
|
||||||
Content = $"[{ComponentsApi.LayoutAttribute.FullTypeName}(typeof({token.Content}))]" + Environment.NewLine,
|
Content = $"[{ComponentsApi.LayoutAttribute.FullTypeName}(typeof({token.Content}))]",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Insert the new attribute on top of the class
|
// Insert the new attribute on top of the class
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(FileKinds.Component, Directive);
|
builder.AddDirective(Directive, FileKinds.Component, FileKinds.ComponentImport);
|
||||||
builder.Features.Add(new ComponentPageDirectivePass());
|
builder.Features.Add(new ComponentPageDirectivePass());
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
for (var i = 0; i < directives.Count; i++)
|
for (var i = 0; i < directives.Count; i++)
|
||||||
{
|
{
|
||||||
var directive = directives[i];
|
var directive = directives[i];
|
||||||
if (directive.Node.IsImported())
|
if (FileKinds.IsComponentImport(codeDocument.GetFileKind()) || directive.Node.IsImported())
|
||||||
{
|
{
|
||||||
directive.Node.Diagnostics.Add(ComponentDiagnosticFactory.CreatePageDirective_CannotBeImported(directive.Node.Source.Value));
|
directive.Node.Diagnostics.Add(ComponentDiagnosticFactory.CreatePageDirective_CannotBeImported(directive.Node.Source.Value));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(FileKinds.Component, Directive);
|
builder.AddDirective(Directive, FileKinds.Component, FileKinds.ComponentImport);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,21 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
internal class DefaultRazorDirectiveFeature : RazorEngineFeatureBase, IRazorDirectiveFeature, IConfigureRazorParserOptionsFeature
|
internal class DefaultRazorDirectiveFeature : RazorEngineFeatureBase, IRazorDirectiveFeature, IConfigureRazorParserOptionsFeature
|
||||||
{
|
{
|
||||||
public ICollection<DirectiveDescriptor> Directives { get; } = new List<DirectiveDescriptor>();
|
// To maintain backwards compatibility, adding to this list will default to legacy file kind.
|
||||||
|
public ICollection<DirectiveDescriptor> Directives
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ICollection<DirectiveDescriptor> result;
|
||||||
|
if (!DirectivesByFileKind.TryGetValue(FileKinds.Legacy, out result))
|
||||||
|
{
|
||||||
|
result = new List<DirectiveDescriptor>();
|
||||||
|
DirectivesByFileKind.Add(FileKinds.Legacy, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IDictionary<string, ICollection<DirectiveDescriptor>> DirectivesByFileKind { get; } = new Dictionary<string, ICollection<DirectiveDescriptor>>(StringComparer.OrdinalIgnoreCase);
|
public IDictionary<string, ICollection<DirectiveDescriptor>> DirectivesByFileKind { get; } = new Dictionary<string, ICollection<DirectiveDescriptor>>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
|
@ -24,22 +38,11 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
options.Directives.Clear();
|
options.Directives.Clear();
|
||||||
|
|
||||||
foreach (var directive in Directives)
|
var fileKind = options.FileKind ?? FileKinds.Legacy;
|
||||||
{
|
if (DirectivesByFileKind.TryGetValue(fileKind, out var directives))
|
||||||
options.Directives.Add(directive);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.FileKind != null && DirectivesByFileKind.TryGetValue(options.FileKind, out var directives))
|
|
||||||
{
|
{
|
||||||
foreach (var directive in directives)
|
foreach (var directive in directives)
|
||||||
{
|
{
|
||||||
// Replace any non-file-kind-specific directives
|
|
||||||
var replaces = options.Directives.Where(d => string.Equals(d.Directive, directive.Directive, StringComparison.Ordinal)).ToArray();
|
|
||||||
foreach (var replace in replaces)
|
|
||||||
{
|
|
||||||
options.Directives.Remove(replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
options.Directives.Add(directive);
|
options.Directives.Add(directive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,17 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
// We need to decide up front if this document is a "component" file. This will affect how
|
// We need to decide up front if this document is a "component" file. This will affect how
|
||||||
// lowering behaves.
|
// lowering behaves.
|
||||||
LoweringVisitor visitor;
|
LoweringVisitor visitor;
|
||||||
if (FileKinds.IsComponent(codeDocument.GetFileKind()) &&
|
if (FileKinds.IsComponentImport(codeDocument.GetFileKind()) &&
|
||||||
|
syntaxTree.Options.FeatureFlags.AllowComponentFileKind)
|
||||||
|
{
|
||||||
|
visitor = new ComponentImportFileKindVisitor(document, builder, syntaxTree.Options.FeatureFlags)
|
||||||
|
{
|
||||||
|
SourceDocument = syntaxTree.Source,
|
||||||
|
};
|
||||||
|
|
||||||
|
visitor.Visit(syntaxTree.Root);
|
||||||
|
}
|
||||||
|
else if (FileKinds.IsComponent(codeDocument.GetFileKind()) &&
|
||||||
syntaxTree.Options.FeatureFlags.AllowComponentFileKind)
|
syntaxTree.Options.FeatureFlags.AllowComponentFileKind)
|
||||||
{
|
{
|
||||||
visitor = new ComponentFileKindVisitor(document, builder, syntaxTree.Options.FeatureFlags)
|
visitor = new ComponentFileKindVisitor(document, builder, syntaxTree.Options.FeatureFlags)
|
||||||
|
|
@ -1856,6 +1866,58 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ComponentImportFileKindVisitor : LoweringVisitor
|
||||||
|
{
|
||||||
|
public ComponentImportFileKindVisitor(
|
||||||
|
DocumentIntermediateNode document,
|
||||||
|
IntermediateNodeBuilder builder,
|
||||||
|
RazorParserFeatureFlags featureFlags)
|
||||||
|
: base(document, builder, featureFlags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DefaultVisit(SyntaxNode node)
|
||||||
|
{
|
||||||
|
base.DefaultVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitMarkupElement(MarkupElementSyntax node)
|
||||||
|
{
|
||||||
|
_document.Diagnostics.Add(
|
||||||
|
ComponentDiagnosticFactory.Create_UnsupportedComponentImportContent(BuildSourceSpanFromNode(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitMarkupCommentBlock(MarkupCommentBlockSyntax node)
|
||||||
|
{
|
||||||
|
_document.Diagnostics.Add(
|
||||||
|
ComponentDiagnosticFactory.Create_UnsupportedComponentImportContent(BuildSourceSpanFromNode(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitMarkupTagHelperElement(MarkupTagHelperElementSyntax node)
|
||||||
|
{
|
||||||
|
_document.Diagnostics.Add(
|
||||||
|
ComponentDiagnosticFactory.Create_UnsupportedComponentImportContent(BuildSourceSpanFromNode(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitCSharpImplicitExpression(CSharpImplicitExpressionSyntax node)
|
||||||
|
{
|
||||||
|
_document.Diagnostics.Add(
|
||||||
|
ComponentDiagnosticFactory.Create_UnsupportedComponentImportContent(BuildSourceSpanFromNode(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitCSharpExplicitExpression(CSharpExplicitExpressionSyntax node)
|
||||||
|
{
|
||||||
|
_document.Diagnostics.Add(
|
||||||
|
ComponentDiagnosticFactory.Create_UnsupportedComponentImportContent(BuildSourceSpanFromNode(node)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitCSharpStatement(CSharpStatementSyntax node)
|
||||||
|
{
|
||||||
|
_document.Diagnostics.Add(
|
||||||
|
ComponentDiagnosticFactory.Create_UnsupportedComponentImportContent(BuildSourceSpanFromNode(node)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ImportsVisitor : LoweringVisitor
|
private class ImportsVisitor : LoweringVisitor
|
||||||
{
|
{
|
||||||
public ImportsVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, RazorParserFeatureFlags featureFlags)
|
public ImportsVisitor(DocumentIntermediateNode document, IntermediateNodeBuilder builder, RazorParserFeatureFlags featureFlags)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,9 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
// The imports come logically before the main razor file and are in the order they
|
// The imports come logically before the main razor file and are in the order they
|
||||||
// should be processed.
|
// should be processed.
|
||||||
DirectiveVisitor visitor = null;
|
DirectiveVisitor visitor = null;
|
||||||
if (FileKinds.IsComponent(codeDocument.GetFileKind()))
|
var parserOptions = codeDocument.GetParserOptions();
|
||||||
|
if (FileKinds.IsComponent(codeDocument.GetFileKind()) &&
|
||||||
|
(parserOptions == null || parserOptions.FeatureFlags.AllowComponentFileKind))
|
||||||
{
|
{
|
||||||
codeDocument.TryComputeNamespaceAndClass(out var currentNamespace, out var _);
|
codeDocument.TryComputeNamespaceAndClass(out var currentNamespace, out var _);
|
||||||
visitor = new ComponentDirectiveVisitor(codeDocument.Source.FilePath, descriptors, currentNamespace);
|
visitor = new ComponentDirectiveVisitor(codeDocument.Source.FilePath, descriptors, currentNamespace);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(Directive);
|
builder.AddDirective(Directive, FileKinds.Legacy, FileKinds.Component);
|
||||||
builder.Features.Add(new FunctionsDirectivePass());
|
builder.Features.Add(new FunctionsDirectivePass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(Directive);
|
builder.AddDirective(Directive, FileKinds.Legacy, FileKinds.Component, FileKinds.ComponentImport);
|
||||||
builder.Features.Add(new ImplementsDirectivePass());
|
builder.Features.Add(new ImplementsDirectivePass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(Directive);
|
builder.AddDirective(Directive, FileKinds.Legacy, FileKinds.Component, FileKinds.ComponentImport);
|
||||||
builder.Features.Add(new InheritsDirectivePass());
|
builder.Features.Add(new InheritsDirectivePass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AddDirective(Directive);
|
builder.AddDirective(Directive, FileKinds.Legacy, FileKinds.Component);
|
||||||
builder.Features.Add(new SectionDirectivePass());
|
builder.Features.Add(new SectionDirectivePass());
|
||||||
builder.AddTargetExtension(new SectionTargetExtension());
|
builder.AddTargetExtension(new SectionTargetExtension());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,23 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
return string.Equals(fileKind, FileKinds.ComponentImport, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(fileKind, FileKinds.ComponentImport, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetComponentFileKindFromFilePath(string filePath)
|
||||||
|
{
|
||||||
|
if (filePath == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(ComponentMetadata.ImportsFileName, Path.GetFileName(filePath), StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return FileKinds.ComponentImport;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FileKinds.Component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetFileKindFromFilePath(string filePath)
|
public static string GetFileKindFromFilePath(string filePath)
|
||||||
{
|
{
|
||||||
if (filePath == null)
|
if (filePath == null)
|
||||||
|
|
|
||||||
|
|
@ -166,35 +166,38 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
/// Adds the specified <see cref="DirectiveDescriptor"/> for the provided file kind.
|
/// Adds the specified <see cref="DirectiveDescriptor"/> for the provided file kind.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
|
/// <param name="builder">The <see cref="RazorProjectEngineBuilder"/>.</param>
|
||||||
/// <param name="fileKind">The file kind, for which to register the directive. See <see cref="FileKinds"/>.</param>
|
|
||||||
/// <param name="directive">The <see cref="DirectiveDescriptor"/> to add.</param>
|
/// <param name="directive">The <see cref="DirectiveDescriptor"/> to add.</param>
|
||||||
|
/// <param name="fileKinds">The file kinds, for which to register the directive. See <see cref="FileKinds"/>.</param>
|
||||||
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
|
/// <returns>The <see cref="RazorProjectEngineBuilder"/>.</returns>
|
||||||
public static RazorProjectEngineBuilder AddDirective(this RazorProjectEngineBuilder builder, string fileKind, DirectiveDescriptor directive)
|
public static RazorProjectEngineBuilder AddDirective(this RazorProjectEngineBuilder builder, DirectiveDescriptor directive, params string[] fileKinds)
|
||||||
{
|
{
|
||||||
if (builder == null)
|
if (builder == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileKind == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(fileKind));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (directive == null)
|
if (directive == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(directive));
|
throw new ArgumentNullException(nameof(directive));
|
||||||
}
|
}
|
||||||
|
|
||||||
var directiveFeature = GetDirectiveFeature(builder);
|
if (fileKinds == null)
|
||||||
|
|
||||||
if (!directiveFeature.DirectivesByFileKind.TryGetValue(fileKind, out var directives))
|
|
||||||
{
|
{
|
||||||
directives = new List<DirectiveDescriptor>();
|
throw new ArgumentNullException(nameof(fileKinds));
|
||||||
directiveFeature.DirectivesByFileKind.Add(fileKind, directives);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
directives.Add(directive);
|
var directiveFeature = GetDirectiveFeature(builder);
|
||||||
|
|
||||||
|
foreach (var fileKind in fileKinds)
|
||||||
|
{
|
||||||
|
if (!directiveFeature.DirectivesByFileKind.TryGetValue(fileKind, out var directives))
|
||||||
|
{
|
||||||
|
directives = new List<DirectiveDescriptor>();
|
||||||
|
directiveFeature.DirectivesByFileKind.Add(fileKind, directives);
|
||||||
|
}
|
||||||
|
|
||||||
|
directives.Add(directive);
|
||||||
|
}
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language.Components;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
using Microsoft.Extensions.CommandLineUtils;
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
|
@ -286,6 +287,10 @@ namespace Microsoft.AspNetCore.Razor.Tools
|
||||||
{
|
{
|
||||||
var outputPath = Path.Combine(projectDirectory, outputs[i]);
|
var outputPath = Path.Combine(projectDirectory, outputs[i]);
|
||||||
var fileKind = fileKinds.Count > 0 ? fileKinds[i] : "mvc";
|
var fileKind = fileKinds.Count > 0 ? fileKinds[i] : "mvc";
|
||||||
|
if (Language.FileKinds.IsComponent(fileKind))
|
||||||
|
{
|
||||||
|
fileKind = Language.FileKinds.GetComponentFileKindFromFilePath(sources[i]);
|
||||||
|
}
|
||||||
|
|
||||||
items[i] = new SourceItem(sources[i], outputs[i], relativePath[i], fileKind);
|
items[i] = new SourceItem(sources[i], outputs[i], relativePath[i], fileKind);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
{
|
{
|
||||||
AdditionalSyntaxTrees = new List<SyntaxTree>();
|
AdditionalSyntaxTrees = new List<SyntaxTree>();
|
||||||
AdditionalRazorItems = new List<RazorProjectItem>();
|
AdditionalRazorItems = new List<RazorProjectItem>();
|
||||||
|
ImportItems = new List<RazorProjectItem>();
|
||||||
|
|
||||||
BaseCompilation = DefaultBaseCompilation;
|
BaseCompilation = DefaultBaseCompilation;
|
||||||
Configuration = RazorConfiguration.Default;
|
Configuration = RazorConfiguration.Default;
|
||||||
|
|
@ -72,6 +73,8 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
|
|
||||||
internal List<RazorProjectItem> AdditionalRazorItems { get; }
|
internal List<RazorProjectItem> AdditionalRazorItems { get; }
|
||||||
|
|
||||||
|
internal List<RazorProjectItem> ImportItems { get; }
|
||||||
|
|
||||||
internal List<SyntaxTree> AdditionalSyntaxTrees { get; }
|
internal List<SyntaxTree> AdditionalSyntaxTrees { get; }
|
||||||
|
|
||||||
internal virtual CSharpCompilation BaseCompilation { get; }
|
internal virtual CSharpCompilation BaseCompilation { get; }
|
||||||
|
|
@ -118,6 +121,8 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
// 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());
|
||||||
|
|
||||||
|
b.Features.Add(new TestImportProjectFeature(ImportItems));
|
||||||
|
|
||||||
if (LineEnding != null)
|
if (LineEnding != null)
|
||||||
{
|
{
|
||||||
b.Phases.Insert(0, new ForceLineEndingPhase(LineEnding));
|
b.Phases.Insert(0, new ForceLineEndingPhase(LineEnding));
|
||||||
|
|
@ -135,7 +140,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
internal RazorProjectItem CreateProjectItem(string cshtmlRelativePath, string cshtmlContent)
|
internal RazorProjectItem CreateProjectItem(string cshtmlRelativePath, string cshtmlContent, string fileKind = null)
|
||||||
{
|
{
|
||||||
var fullPath = WorkingDirectory + PathSeparator + cshtmlRelativePath;
|
var fullPath = WorkingDirectory + PathSeparator + cshtmlRelativePath;
|
||||||
|
|
||||||
|
|
@ -156,7 +161,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
physicalPath: fullPath,
|
physicalPath: fullPath,
|
||||||
relativePhysicalPath: cshtmlRelativePath,
|
relativePhysicalPath: cshtmlRelativePath,
|
||||||
basePath: WorkingDirectory,
|
basePath: WorkingDirectory,
|
||||||
fileKind: FileKind)
|
fileKind: fileKind ?? FileKind)
|
||||||
{
|
{
|
||||||
Content = cshtmlContent.TrimStart(),
|
Content = cshtmlContent.TrimStart(),
|
||||||
};
|
};
|
||||||
|
|
@ -167,7 +172,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
return CompileToCSharp(DefaultFileName, cshtmlContent, throwOnFailure);
|
return CompileToCSharp(DefaultFileName, cshtmlContent, throwOnFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CompileToCSharpResult CompileToCSharp(string cshtmlRelativePath, string cshtmlContent, bool throwOnFailure = true)
|
protected CompileToCSharpResult CompileToCSharp(string cshtmlRelativePath, string cshtmlContent, bool throwOnFailure = true, string fileKind = null)
|
||||||
{
|
{
|
||||||
if (DeclarationOnly && DesignTime)
|
if (DeclarationOnly && DesignTime)
|
||||||
{
|
{
|
||||||
|
|
@ -197,7 +202,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result of generating declarations
|
// Result of generating declarations
|
||||||
var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent);
|
var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent, fileKind);
|
||||||
codeDocument = projectEngine.ProcessDeclarationOnly(projectItem);
|
codeDocument = projectEngine.ProcessDeclarationOnly(projectItem);
|
||||||
var declaration = new CompileToCSharpResult
|
var declaration = new CompileToCSharpResult
|
||||||
{
|
{
|
||||||
|
|
@ -243,7 +248,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
// This will include the built-in components.
|
// This will include the built-in components.
|
||||||
var projectEngine = CreateProjectEngine(Configuration, BaseCompilation.References.ToArray());
|
var projectEngine = CreateProjectEngine(Configuration, BaseCompilation.References.ToArray());
|
||||||
|
|
||||||
var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent);
|
var projectItem = CreateProjectItem(cshtmlRelativePath, cshtmlContent, fileKind);
|
||||||
|
|
||||||
RazorCodeDocument codeDocument;
|
RazorCodeDocument codeDocument;
|
||||||
if (DeclarationOnly)
|
if (DeclarationOnly)
|
||||||
|
|
@ -456,5 +461,22 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
|
||||||
codeDocument.Items[key] = LineEnding;
|
codeDocument.Items[key] = LineEnding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestImportProjectFeature : IImportProjectFeature
|
||||||
|
{
|
||||||
|
private List<RazorProjectItem> _imports;
|
||||||
|
|
||||||
|
public TestImportProjectFeature(List<RazorProjectItem> imports)
|
||||||
|
{
|
||||||
|
_imports = imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorProjectEngine ProjectEngine { get; set; }
|
||||||
|
|
||||||
|
public IReadOnlyList<RazorProjectItem> GetImports(RazorProjectItem projectItem)
|
||||||
|
{
|
||||||
|
return _imports;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue