Add @addtaghelper directive.
- Also added some infrastructure pieces for it such as the ITagHelperDescriptorResolver and the default implementation TagHelperDescriptorResolver which will be filled out in a later commit. - Reworked some extensibility points to allow accessibility of the descriptor resolvers per offline discussions. #111
This commit is contained in:
parent
05d8193775
commit
b67b8dae3d
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||||
|
|
||||||
new CSharpHelperVisitor(csharpCodeVisitor, writer, Context).Accept(Tree.Chunks);
|
new CSharpHelperVisitor(csharpCodeVisitor, writer, Context).Accept(Tree.Chunks);
|
||||||
new CSharpTypeMemberVisitor(csharpCodeVisitor, writer, Context).Accept(Tree.Chunks);
|
new CSharpTypeMemberVisitor(csharpCodeVisitor, writer, Context).Accept(Tree.Chunks);
|
||||||
new CSharpDesignTimeHelpersVisitor(writer, Context).AcceptTree(Tree);
|
new CSharpDesignTimeHelpersVisitor(csharpCodeVisitor, writer, Context).AcceptTree(Tree);
|
||||||
new CSharpTagHelperFieldDeclarationVisitor(writer, Context).Accept(Tree.Chunks);
|
new CSharpTagHelperFieldDeclarationVisitor(writer, Context).Accept(Tree.Chunks);
|
||||||
|
|
||||||
BuildConstructor(writer);
|
BuildConstructor(writer);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||||
private const string TemplateWriterName = "__razor_template_writer";
|
private const string TemplateWriterName = "__razor_template_writer";
|
||||||
|
|
||||||
private CSharpPaddingBuilder _paddingBuilder;
|
private CSharpPaddingBuilder _paddingBuilder;
|
||||||
|
private CSharpTagHelperCodeRenderer _tagHelperCodeRenderer;
|
||||||
|
|
||||||
public CSharpCodeVisitor(CSharpCodeWriter writer, CodeBuilderContext context)
|
public CSharpCodeVisitor(CSharpCodeWriter writer, CodeBuilderContext context)
|
||||||
: base(writer, context)
|
: base(writer, context)
|
||||||
|
|
@ -25,7 +26,22 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||||
TagHelperRenderer = new CSharpTagHelperCodeRenderer(this, writer, context);
|
TagHelperRenderer = new CSharpTagHelperCodeRenderer(this, writer, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CSharpTagHelperCodeRenderer TagHelperRenderer { get; set; }
|
public CSharpTagHelperCodeRenderer TagHelperRenderer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _tagHelperCodeRenderer;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(TagHelperRenderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
_tagHelperCodeRenderer = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Visit(TagHelperChunk chunk)
|
protected override void Visit(TagHelperChunk chunk)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||||
{
|
{
|
||||||
public class CSharpDesignTimeHelpersVisitor : CodeVisitor<CSharpCodeWriter>
|
public class CSharpDesignTimeHelpersVisitor : CodeVisitor<CSharpCodeWriter>
|
||||||
|
|
@ -8,10 +11,21 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||||
internal const string InheritsHelper = "__inheritsHelper";
|
internal const string InheritsHelper = "__inheritsHelper";
|
||||||
internal const string DesignTimeHelperMethodName = "__RazorDesignTimeHelpers__";
|
internal const string DesignTimeHelperMethodName = "__RazorDesignTimeHelpers__";
|
||||||
|
|
||||||
|
private const string TagHelperDirectiveSyntaxHelper = "__tagHelperDirectiveSyntaxHelper";
|
||||||
private const int DisableVariableNamingWarnings = 219;
|
private const int DisableVariableNamingWarnings = 219;
|
||||||
|
|
||||||
public CSharpDesignTimeHelpersVisitor(CSharpCodeWriter writer, CodeBuilderContext context)
|
private readonly CSharpCodeVisitor _csharpCodeVisitor;
|
||||||
: base(writer, context) { }
|
|
||||||
|
private bool _initializedTagHelperDirectiveSyntaxHelper;
|
||||||
|
|
||||||
|
public CSharpDesignTimeHelpersVisitor([NotNull] CSharpCodeVisitor csharpCodeVisitor,
|
||||||
|
[NotNull] CSharpCodeWriter writer,
|
||||||
|
[NotNull] CodeBuilderContext context)
|
||||||
|
|
||||||
|
: base(writer, context)
|
||||||
|
{
|
||||||
|
_csharpCodeVisitor = csharpCodeVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
public void AcceptTree(CodeTree tree)
|
public void AcceptTree(CodeTree tree)
|
||||||
{
|
{
|
||||||
|
|
@ -43,5 +57,29 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Visit(AddTagHelperChunk chunk)
|
||||||
|
{
|
||||||
|
// We should always be in design time mode because of the calling AcceptTree method verification.
|
||||||
|
Debug.Assert(Context.Host.DesignTimeMode);
|
||||||
|
|
||||||
|
if (!_initializedTagHelperDirectiveSyntaxHelper)
|
||||||
|
{
|
||||||
|
_initializedTagHelperDirectiveSyntaxHelper = true;
|
||||||
|
Writer.WriteVariableDeclaration("string", TagHelperDirectiveSyntaxHelper, "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.WriteStartAssignment(TagHelperDirectiveSyntaxHelper);
|
||||||
|
|
||||||
|
// The parsing mechanism for the AddTagHelperChunk (CSharpCodeParser.TagHelperDirective()) removes quotes
|
||||||
|
// that surround the chunk.LookupText.
|
||||||
|
_csharpCodeVisitor.CreateExpressionCodeMapping(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"\"{0}\"", chunk.LookupText),
|
||||||
|
chunk);
|
||||||
|
|
||||||
|
Writer.WriteLine(";");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,10 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
|
||||||
{
|
{
|
||||||
Visit((TagHelperChunk)chunk);
|
Visit((TagHelperChunk)chunk);
|
||||||
}
|
}
|
||||||
|
else if (chunk is AddTagHelperChunk)
|
||||||
|
{
|
||||||
|
Visit((AddTagHelperChunk)chunk);
|
||||||
|
}
|
||||||
else if(chunk is SetLayoutChunk)
|
else if(chunk is SetLayoutChunk)
|
||||||
{
|
{
|
||||||
Visit((SetLayoutChunk)chunk);
|
Visit((SetLayoutChunk)chunk);
|
||||||
|
|
@ -115,6 +119,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
|
||||||
protected abstract void Visit(ExpressionChunk chunk);
|
protected abstract void Visit(ExpressionChunk chunk);
|
||||||
protected abstract void Visit(StatementChunk chunk);
|
protected abstract void Visit(StatementChunk chunk);
|
||||||
protected abstract void Visit(TagHelperChunk chunk);
|
protected abstract void Visit(TagHelperChunk chunk);
|
||||||
|
protected abstract void Visit(AddTagHelperChunk chunk);
|
||||||
protected abstract void Visit(UsingChunk chunk);
|
protected abstract void Visit(UsingChunk chunk);
|
||||||
protected abstract void Visit(ChunkBlock chunk);
|
protected abstract void Visit(ChunkBlock chunk);
|
||||||
protected abstract void Visit(DynamicCodeAttributeChunk chunk);
|
protected abstract void Visit(DynamicCodeAttributeChunk chunk);
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
|
||||||
protected override void Visit(TagHelperChunk chunk)
|
protected override void Visit(TagHelperChunk chunk)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
protected override void Visit(AddTagHelperChunk chunk)
|
||||||
|
{
|
||||||
|
}
|
||||||
protected override void Visit(LiteralCodeAttributeChunk chunk)
|
protected override void Visit(LiteralCodeAttributeChunk chunk)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Generator.Compiler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="Chunk"/> used to look up <see cref="TagHelpers.TagHelperDescriptor"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public class AddTagHelperChunk : Chunk
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Text used to look up <see cref="TagHelpers.TagHelperDescriptor"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public string LookupText { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,6 +39,14 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddAddTagHelperChunk(string lookupText, SyntaxTreeNode association)
|
||||||
|
{
|
||||||
|
AddChunk(new AddTagHelperChunk
|
||||||
|
{
|
||||||
|
LookupText = lookupText
|
||||||
|
}, association);
|
||||||
|
}
|
||||||
|
|
||||||
public void AddLiteralChunk(string literal, SyntaxTreeNode association)
|
public void AddLiteralChunk(string literal, SyntaxTreeNode association)
|
||||||
{
|
{
|
||||||
// If the previous chunk was also a LiteralChunk, append the content of the current node to the previous one.
|
// If the previous chunk was also a LiteralChunk, append the content of the current node to the previous one.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Generator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="SpanCodeGenerator"/> responsible for generating <see cref="Compiler.AddTagHelperChunk"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public class AddTagHelperCodeGenerator : SpanCodeGenerator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates a new <see cref="AddTagHelperCodeGenerator"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lookupText">
|
||||||
|
/// Text used to look up <see cref="TagHelpers.TagHelperDescriptor"/>s.
|
||||||
|
/// </param>
|
||||||
|
public AddTagHelperCodeGenerator(string lookupText)
|
||||||
|
{
|
||||||
|
LookupText = lookupText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text used to look up <see cref="TagHelpers.TagHelperDescriptor"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public string LookupText { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a <see cref="Compiler.AddTagHelperChunk"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">
|
||||||
|
/// The <see cref="Span"/> responsible for this <see cref="AddTagHelperCodeGenerator"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="context">A <see cref="CodeGeneratorContext"/> instance that contains information about
|
||||||
|
/// the current code generation process.</param>
|
||||||
|
public override void GenerateCode(Span target, CodeGeneratorContext context)
|
||||||
|
{
|
||||||
|
context.CodeTreeBuilder.AddAddTagHelperChunk(LookupText, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
{
|
{
|
||||||
private void SetupDirectives()
|
private void SetupDirectives()
|
||||||
{
|
{
|
||||||
|
MapDirectives(AddTagHelperDirective, SyntaxConstants.CSharp.AddTagHelperKeyword);
|
||||||
MapDirectives(InheritsDirective, SyntaxConstants.CSharp.InheritsKeyword);
|
MapDirectives(InheritsDirective, SyntaxConstants.CSharp.InheritsKeyword);
|
||||||
MapDirectives(FunctionsDirective, SyntaxConstants.CSharp.FunctionsKeyword);
|
MapDirectives(FunctionsDirective, SyntaxConstants.CSharp.FunctionsKeyword);
|
||||||
MapDirectives(SectionDirective, SyntaxConstants.CSharp.SectionKeyword);
|
MapDirectives(SectionDirective, SyntaxConstants.CSharp.SectionKeyword);
|
||||||
|
|
@ -27,6 +28,14 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
MapDirectives(SessionStateDirective, SyntaxConstants.CSharp.SessionStateKeyword);
|
MapDirectives(SessionStateDirective, SyntaxConstants.CSharp.SessionStateKeyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void AddTagHelperDirective()
|
||||||
|
{
|
||||||
|
TagHelperDirective(SyntaxConstants.CSharp.AddTagHelperKeyword, (lookupText) =>
|
||||||
|
{
|
||||||
|
return new AddTagHelperCodeGenerator(lookupText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void LayoutDirective()
|
protected virtual void LayoutDirective()
|
||||||
{
|
{
|
||||||
AssertDirective(SyntaxConstants.CSharp.LayoutKeyword);
|
AssertDirective(SyntaxConstants.CSharp.LayoutKeyword);
|
||||||
|
|
@ -498,5 +507,65 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
CompleteBlock();
|
CompleteBlock();
|
||||||
Output(SpanKind.Code);
|
Output(SpanKind.Code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TagHelperDirective(string keyword, Func<string, SpanCodeGenerator> codeGeneratorBuilder)
|
||||||
|
{
|
||||||
|
AssertDirective(keyword);
|
||||||
|
|
||||||
|
// Accept the directive name
|
||||||
|
AcceptAndMoveNext();
|
||||||
|
|
||||||
|
// Set the block type
|
||||||
|
Context.CurrentBlock.Type = BlockType.Directive;
|
||||||
|
|
||||||
|
var foundWhitespace = At(CSharpSymbolType.WhiteSpace);
|
||||||
|
AcceptWhile(CSharpSymbolType.WhiteSpace);
|
||||||
|
|
||||||
|
// If we found whitespace then any content placed within the whitespace MAY cause a destructive change
|
||||||
|
// to the document. We can't accept it.
|
||||||
|
Output(SpanKind.MetaCode, foundWhitespace ? AcceptedCharacters.None : AcceptedCharacters.Any);
|
||||||
|
|
||||||
|
if (EndOfFile || At(CSharpSymbolType.NewLine))
|
||||||
|
{
|
||||||
|
Context.OnError(CurrentLocation, RazorResources.FormatParseError_DirectiveMustHaveValue(keyword));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Need to grab the current location before we accept until the end of the line.
|
||||||
|
var startLocation = CurrentLocation;
|
||||||
|
|
||||||
|
// Parse to the end of the line. Essentially accepts anything until end of line, comments, invalid code
|
||||||
|
// etc.
|
||||||
|
AcceptUntil(CSharpSymbolType.NewLine);
|
||||||
|
|
||||||
|
// Pull out the value minus the spaces at the end
|
||||||
|
var rawValue = Span.GetContent().Value.TrimEnd();
|
||||||
|
var startsWithQuote = rawValue.StartsWith("\"", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// If the value starts with a quote then we should generate appropriate C# code to colorize the value.
|
||||||
|
if (startsWithQuote)
|
||||||
|
{
|
||||||
|
// Set up code generation
|
||||||
|
// The generated chunk of this code generator is picked up by CSharpDesignTimeHelpersVisitor which
|
||||||
|
// renders the C# to colorize the user provided value. We trim the quotes around the user's value
|
||||||
|
// so when we render the code we can project the users value into double quotes to not invoke C#
|
||||||
|
// IntelliSense.
|
||||||
|
Span.CodeGenerator = codeGeneratorBuilder(rawValue.Trim('"'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We expect the directive to be surrounded in quotes.
|
||||||
|
// The format for taghelper directives are: @directivename "SomeValue"
|
||||||
|
if (!startsWithQuote ||
|
||||||
|
!rawValue.EndsWith("\"", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Context.OnError(startLocation,
|
||||||
|
RazorResources.FormatParseError_DirectiveMustBeSurroundedByQuotes(keyword));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the span and finish the block
|
||||||
|
CompleteBlock();
|
||||||
|
Output(SpanKind.Code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
|
|
||||||
internal static ISet<string> DefaultKeywords = new HashSet<string>()
|
internal static ISet<string> DefaultKeywords = new HashSet<string>()
|
||||||
{
|
{
|
||||||
|
SyntaxConstants.CSharp.AddTagHelperKeyword,
|
||||||
"if",
|
"if",
|
||||||
"do",
|
"do",
|
||||||
"try",
|
"try",
|
||||||
|
|
|
||||||
|
|
@ -17,25 +17,16 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
{
|
{
|
||||||
public class RazorParser
|
public class RazorParser
|
||||||
{
|
{
|
||||||
public RazorParser(ParserBase codeParser, ParserBase markupParser)
|
private ITagHelperDescriptorResolver _tagHelperDescriptorResolver;
|
||||||
{
|
|
||||||
if (codeParser == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("codeParser");
|
|
||||||
}
|
|
||||||
if (markupParser == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("markupParser");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public RazorParser([NotNull] ParserBase codeParser,
|
||||||
|
[NotNull] ParserBase markupParser,
|
||||||
|
ITagHelperDescriptorResolver tagHelperDescriptorResolver)
|
||||||
|
{
|
||||||
|
_tagHelperDescriptorResolver = tagHelperDescriptorResolver;
|
||||||
MarkupParser = markupParser;
|
MarkupParser = markupParser;
|
||||||
CodeParser = codeParser;
|
CodeParser = codeParser;
|
||||||
|
|
||||||
// TODO: As part of https://github.com/aspnet/Razor/issues/111 and
|
|
||||||
// https://github.com/aspnet/Razor/issues/112 pull the provider from some sort of tag helper locator
|
|
||||||
// object.
|
|
||||||
var provider = new TagHelperDescriptorProvider(Enumerable.Empty<TagHelperDescriptor>());
|
|
||||||
|
|
||||||
Optimizers = new List<ISyntaxTreeRewriter>()
|
Optimizers = new List<ISyntaxTreeRewriter>()
|
||||||
{
|
{
|
||||||
// TODO: Modify the below WhiteSpaceRewriter & ConditionalAttributeCollapser to handle
|
// TODO: Modify the below WhiteSpaceRewriter & ConditionalAttributeCollapser to handle
|
||||||
|
|
@ -45,8 +36,6 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
new WhiteSpaceRewriter(MarkupParser.BuildSpan),
|
new WhiteSpaceRewriter(MarkupParser.BuildSpan),
|
||||||
// Collapse conditional attributes where the entire value is literal
|
// Collapse conditional attributes where the entire value is literal
|
||||||
new ConditionalAttributeCollapser(MarkupParser.BuildSpan),
|
new ConditionalAttributeCollapser(MarkupParser.BuildSpan),
|
||||||
// Enables tag helpers
|
|
||||||
new TagHelperParseTreeRewriter(provider),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,6 +142,16 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
current = rewriter.Rewrite(current);
|
current = rewriter.Rewrite(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_tagHelperDescriptorResolver != null)
|
||||||
|
{
|
||||||
|
var tagHelperRegistrationVisitor = new TagHelperRegistrationVisitor(_tagHelperDescriptorResolver);
|
||||||
|
var tagHelperProvider = tagHelperRegistrationVisitor.CreateProvider(current);
|
||||||
|
|
||||||
|
var tagHelperParseTreeRewriter = new TagHelperParseTreeRewriter(tagHelperProvider);
|
||||||
|
// Rewrite the document to utilize tag helpers
|
||||||
|
current = tagHelperParseTreeRewriter.Rewrite(current);
|
||||||
|
}
|
||||||
|
|
||||||
// Link the leaf nodes into a chain
|
// Link the leaf nodes into a chain
|
||||||
Span prev = null;
|
Span prev = null;
|
||||||
foreach (Span node in current.Flatten())
|
foreach (Span node in current.Flatten())
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ namespace Microsoft.AspNet.Razor.Parser
|
||||||
public static class CSharp
|
public static class CSharp
|
||||||
{
|
{
|
||||||
public static readonly int UsingKeywordLength = 5;
|
public static readonly int UsingKeywordLength = 5;
|
||||||
|
public static readonly string AddTagHelperKeyword = "addtaghelper";
|
||||||
public static readonly string InheritsKeyword = "inherits";
|
public static readonly string InheritsKeyword = "inherits";
|
||||||
public static readonly string FunctionsKeyword = "functions";
|
public static readonly string FunctionsKeyword = "functions";
|
||||||
public static readonly string SectionKeyword = "section";
|
public static readonly string SectionKeyword = "section";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNet.Razor.Generator;
|
||||||
|
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||||
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
|
||||||
|
{
|
||||||
|
public class TagHelperRegistrationVisitor : ParserVisitor
|
||||||
|
{
|
||||||
|
private readonly ITagHelperDescriptorResolver _descriptorResolver;
|
||||||
|
|
||||||
|
private HashSet<TagHelperDescriptor> _descriptors;
|
||||||
|
|
||||||
|
public TagHelperRegistrationVisitor(ITagHelperDescriptorResolver descriptorResolver)
|
||||||
|
{
|
||||||
|
_descriptorResolver = descriptorResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagHelperDescriptorProvider CreateProvider(Block root)
|
||||||
|
{
|
||||||
|
_descriptors = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default);
|
||||||
|
|
||||||
|
// This will recurse through the syntax tree.
|
||||||
|
VisitBlock(root);
|
||||||
|
|
||||||
|
return new TagHelperDescriptorProvider(_descriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void VisitSpan(Span span)
|
||||||
|
{
|
||||||
|
// We're only interested in spans with an AddTagHelperCodeGenerator.
|
||||||
|
if (span.CodeGenerator is AddTagHelperCodeGenerator)
|
||||||
|
{
|
||||||
|
if (_descriptorResolver == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
RazorResources.FormatTagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver(
|
||||||
|
SyntaxConstants.CSharp.AddTagHelperKeyword,
|
||||||
|
nameof(TagHelperDescriptorResolver),
|
||||||
|
nameof(RazorParser)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var addGenerator = (AddTagHelperCodeGenerator)span.CodeGenerator;
|
||||||
|
|
||||||
|
// Look up all the descriptors associated with the "LookupText".
|
||||||
|
var descriptors = _descriptorResolver.Resolve(addGenerator.LookupText);
|
||||||
|
|
||||||
|
// Add all the found descriptors to our HashSet.
|
||||||
|
foreach (var descriptor in descriptors)
|
||||||
|
{
|
||||||
|
_descriptors.Add(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1494,6 +1494,54 @@ namespace Microsoft.AspNet.Razor
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Directive '{0}' must have a value.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ParseError_DirectiveMustHaveValue
|
||||||
|
{
|
||||||
|
get { return GetString("ParseError_DirectiveMustHaveValue"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Directive '{0}' must have a value.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatParseError_DirectiveMustHaveValue(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_DirectiveMustHaveValue"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Directive '{0}'s value must be surrounded in double quotes.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ParseError_DirectiveMustBeSurroundedByQuotes
|
||||||
|
{
|
||||||
|
get { return GetString("ParseError_DirectiveMustBeSurroundedByQuotes"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Directive '{0}'s value must be surrounded in double quotes.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatParseError_DirectiveMustBeSurroundedByQuotes(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_DirectiveMustBeSurroundedByQuotes"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cannot use directive '{0}' when a {1} has not been provided to the {2}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver
|
||||||
|
{
|
||||||
|
get { return GetString("TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cannot use directive '{0}' when a {1} has not been provided to the {2}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatTagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver(object p0, object p1, object p2)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver"), p0, p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNet.Razor.Generator;
|
||||||
using Microsoft.AspNet.Razor.Generator.Compiler;
|
using Microsoft.AspNet.Razor.Generator.Compiler;
|
||||||
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
|
using Microsoft.AspNet.Razor.Generator.Compiler.CSharp;
|
||||||
using Microsoft.AspNet.Razor.Parser;
|
using Microsoft.AspNet.Razor.Parser;
|
||||||
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor
|
namespace Microsoft.AspNet.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -160,6 +161,12 @@ namespace Microsoft.AspNet.Razor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Document this as part of https://github.com/aspnet/Razor/issues/99
|
||||||
|
public virtual ITagHelperDescriptorResolver CreateTagHelperDescriptorResolver()
|
||||||
|
{
|
||||||
|
return new TagHelperDescriptorResolver();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an instance of the code parser and is provided an opportunity to decorate or replace it
|
/// Gets an instance of the code parser and is provided an opportunity to decorate or replace it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -415,4 +415,13 @@ Instead, wrap the contents of the block in "{{}}":
|
||||||
<data name="TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols" xml:space="preserve">
|
<data name="TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols" xml:space="preserve">
|
||||||
<value>TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.</value>
|
<value>TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ParseError_DirectiveMustHaveValue" xml:space="preserve">
|
||||||
|
<value>Directive '{0}' must have a value.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ParseError_DirectiveMustBeSurroundedByQuotes" xml:space="preserve">
|
||||||
|
<value>Directive '{0}'s value must be surrounded in double quotes.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TagHelpers_CannotUseDirectiveWithNoTagHelperDescriptorResolver" xml:space="preserve">
|
||||||
|
<value>Cannot use directive '{0}' when a {1} has not been provided to the {2}.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -269,11 +269,13 @@ namespace Microsoft.AspNet.Razor
|
||||||
|
|
||||||
protected internal virtual RazorParser CreateParser()
|
protected internal virtual RazorParser CreateParser()
|
||||||
{
|
{
|
||||||
ParserBase codeParser = Host.CodeLanguage.CreateCodeParser();
|
var codeParser = Host.CodeLanguage.CreateCodeParser();
|
||||||
ParserBase markupParser = Host.CreateMarkupParser();
|
var markupParser = Host.CreateMarkupParser();
|
||||||
|
var tagHelperDescriptorResolver = Host.CreateTagHelperDescriptorResolver();
|
||||||
|
|
||||||
return new RazorParser(Host.DecorateCodeParser(codeParser),
|
return new RazorParser(Host.DecorateCodeParser(codeParser),
|
||||||
Host.DecorateMarkupParser(markupParser))
|
Host.DecorateMarkupParser(markupParser),
|
||||||
|
tagHelperDescriptorResolver)
|
||||||
{
|
{
|
||||||
DesignTimeMode = Host.DesignTimeMode
|
DesignTimeMode = Host.DesignTimeMode
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
// TODO: Document this class as part of https://github.com/aspnet/Razor/issues/99
|
||||||
|
|
||||||
|
public interface ITagHelperDescriptorResolver
|
||||||
|
{
|
||||||
|
IEnumerable<TagHelperDescriptor> Resolve(string lookupText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.TagHelpers
|
||||||
|
{
|
||||||
|
// TODO: Implement this class as part of https://github.com/aspnet/Razor/issues/99
|
||||||
|
|
||||||
|
public class TagHelperDescriptorResolver : ITagHelperDescriptorResolver
|
||||||
|
{
|
||||||
|
public IEnumerable<TagHelperDescriptor> Resolve(string lookupText)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<TagHelperDescriptor>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue