Set file path from RazorSourceDocument in syntax tree
This commit is contained in:
parent
6fbbd5d148
commit
cab6eea663
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
|
||||
public virtual IEnumerable<TSymbol> TokenizeString(SourceLocation start, string input)
|
||||
{
|
||||
using (var reader = new SeekableTextReader(input))
|
||||
using (var reader = new SeekableTextReader(input, start.FilePath))
|
||||
{
|
||||
var tok = CreateTokenizer(reader);
|
||||
TSymbol sym;
|
||||
|
|
|
|||
|
|
@ -11,20 +11,23 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
internal class LineTrackingStringBuffer
|
||||
{
|
||||
private readonly IList<TextLine> _lines;
|
||||
private readonly string _filePath;
|
||||
private TextLine _currentLine;
|
||||
private TextLine _endLine;
|
||||
|
||||
public LineTrackingStringBuffer(string content)
|
||||
: this(content.ToCharArray())
|
||||
public LineTrackingStringBuffer(string content, string filePath)
|
||||
: this(content.ToCharArray(), filePath)
|
||||
{
|
||||
}
|
||||
|
||||
public LineTrackingStringBuffer(char[] content)
|
||||
public LineTrackingStringBuffer(char[] content, string filePath)
|
||||
{
|
||||
_endLine = new TextLine(0, 0);
|
||||
_lines = new List<TextLine>() { _endLine };
|
||||
|
||||
Append(content);
|
||||
|
||||
_filePath = filePath;
|
||||
}
|
||||
|
||||
public int Length
|
||||
|
|
@ -34,7 +37,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
|
||||
public SourceLocation EndLocation
|
||||
{
|
||||
get { return new SourceLocation(Length, _lines.Count - 1, _lines[_lines.Count - 1].Length); }
|
||||
get { return new SourceLocation(_filePath, Length, _lines.Count - 1, _lines[_lines.Count - 1].Length); }
|
||||
}
|
||||
|
||||
public CharacterReference CharAt(int absoluteIndex)
|
||||
|
|
@ -45,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
throw new ArgumentOutOfRangeException(nameof(absoluteIndex));
|
||||
}
|
||||
var idx = absoluteIndex - line.Start;
|
||||
return new CharacterReference(line.Content[idx], new SourceLocation(absoluteIndex, line.Index, idx));
|
||||
return new CharacterReference(line.Content[idx], new SourceLocation(_filePath, absoluteIndex, line.Index, idx));
|
||||
}
|
||||
|
||||
private void Append(char[] content)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
var chars = new char[source.Length];
|
||||
source.CopyTo(0, chars, 0, source.Length);
|
||||
|
||||
var reader = new SeekableTextReader(chars);
|
||||
var reader = new SeekableTextReader(chars, source.FileName);
|
||||
|
||||
var context = new ParserContext(reader, Options.DesignTimeMode);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,20 +10,22 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
{
|
||||
private readonly LineTrackingStringBuffer _buffer;
|
||||
private int _position = 0;
|
||||
private SourceLocation _location = SourceLocation.Zero;
|
||||
private SourceLocation _location;
|
||||
private char? _current;
|
||||
|
||||
public SeekableTextReader(string source) : this(source.ToCharArray()) { }
|
||||
public SeekableTextReader(string source, string filePath) : this(source.ToCharArray(), filePath) { }
|
||||
|
||||
public SeekableTextReader(char[] source)
|
||||
public SeekableTextReader(char[] source, string filePath)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
_buffer = new LineTrackingStringBuffer(source);
|
||||
_buffer = new LineTrackingStringBuffer(source, filePath);
|
||||
UpdateState();
|
||||
|
||||
_location = new SourceLocation(filePath, 0, 0, 0);
|
||||
}
|
||||
|
||||
public SourceLocation Location => _location;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
@section Baz {
|
||||
}
|
||||
}";
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content);
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
|
||||
var codeDocument = RazorCodeDocument.Create(sourceDocument);
|
||||
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
@section Baz {
|
||||
}
|
||||
}";
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content);
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
|
||||
var codeDocument = RazorCodeDocument.Create(sourceDocument);
|
||||
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
|
||||
var erroredOriginalTree = RazorSyntaxTree.Create(
|
||||
|
|
|
|||
|
|
@ -78,11 +78,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests
|
|||
// Arrange
|
||||
var engine = RazorEngine.Create();
|
||||
|
||||
var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@!!!"));
|
||||
var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@!!!", fileName: "test.cshtml"));
|
||||
|
||||
var expected = RazorDiagnostic.Create(new RazorError(
|
||||
LegacyResources.FormatParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS("!"),
|
||||
new SourceLocation(1, 0, 1),
|
||||
new SourceLocation("test.cshtml", 1, 0, 1),
|
||||
length: 1));
|
||||
|
||||
// Act
|
||||
|
|
@ -100,11 +100,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests
|
|||
// Arrange
|
||||
var engine = RazorEngine.CreateDesignTime();
|
||||
|
||||
var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@{"));
|
||||
var document = RazorCodeDocument.Create(TestRazorSourceDocument.Create("@{", fileName: "test.cshtml"));
|
||||
|
||||
var expected = RazorDiagnostic.Create(new RazorError(
|
||||
LegacyResources.FormatParseError_Expected_EndOfBlock_Before_EOF(LegacyResources.BlockName_Code, "}", "{"),
|
||||
new SourceLocation(1, 0, 1),
|
||||
new SourceLocation("test.cshtml", 1, 0, 1),
|
||||
length: 1));
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -10,17 +10,17 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
[Fact]
|
||||
public void CtorInitializesProperties()
|
||||
{
|
||||
var buffer = new LineTrackingStringBuffer(string.Empty);
|
||||
var buffer = new LineTrackingStringBuffer(string.Empty, "test.cshtml");
|
||||
Assert.Equal(0, buffer.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CharAtCorrectlyReturnsLocation()
|
||||
{
|
||||
var buffer = new LineTrackingStringBuffer("foo\rbar\nbaz\r\nbiz");
|
||||
LineTrackingStringBuffer.CharacterReference chr = buffer.CharAt(14);
|
||||
var buffer = new LineTrackingStringBuffer("foo\rbar\nbaz\r\nbiz", "test.cshtml");
|
||||
var chr = buffer.CharAt(14);
|
||||
Assert.Equal('i', chr.Character);
|
||||
Assert.Equal(new SourceLocation(14, 3, 1), chr.Location);
|
||||
Assert.Equal(new SourceLocation("test.cshtml", 14, 3, 1), chr.Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,26 +34,36 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
|
||||
internal virtual RazorSyntaxTree ParseDocument(string document, bool designTime = false)
|
||||
{
|
||||
using (var reader = new SeekableTextReader(document))
|
||||
{
|
||||
var options = RazorParserOptions.CreateDefaultOptions();
|
||||
options.DesignTimeMode = designTime;
|
||||
var source = TestRazorSourceDocument.Create(document);
|
||||
var reader = new SeekableTextReader(document, filePath: null);
|
||||
|
||||
var parser = new RazorParser(options);
|
||||
var context = new ParserContext(reader, designTime);
|
||||
|
||||
var tree = parser.Parse(TestRazorSourceDocument.Create(document));
|
||||
var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass();
|
||||
tree = defaultDirectivePass.Execute(codeDocument: null, syntaxTree: tree);
|
||||
var codeParser = new CSharpCodeParser(context);
|
||||
var markupParser = new HtmlMarkupParser(context);
|
||||
|
||||
return tree;
|
||||
}
|
||||
codeParser.HtmlParser = markupParser;
|
||||
markupParser.CodeParser = codeParser;
|
||||
|
||||
markupParser.ParseDocument();
|
||||
|
||||
var root = context.Builder.Build();
|
||||
var diagnostics = context.ErrorSink.Errors?.Select(error => RazorDiagnostic.Create(error));
|
||||
var options = RazorParserOptions.CreateDefaultOptions();
|
||||
options.DesignTimeMode = designTime;
|
||||
|
||||
var tree = RazorSyntaxTree.Create(root, source, diagnostics, options);
|
||||
var defaultDirectivePass = new DefaultDirectiveSyntaxTreePass();
|
||||
tree = defaultDirectivePass.Execute(codeDocument: null, syntaxTree: tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
internal virtual RazorSyntaxTree ParseHtmlBlock(string document, bool designTime = false)
|
||||
{
|
||||
var source = TestRazorSourceDocument.Create(document);
|
||||
|
||||
using (var reader = new SeekableTextReader(document))
|
||||
using (var reader = new SeekableTextReader(document, filePath: null))
|
||||
{
|
||||
var context = new ParserContext(reader, designTime);
|
||||
|
||||
|
|
@ -86,7 +96,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
{
|
||||
var source = TestRazorSourceDocument.Create(document);
|
||||
|
||||
using (var reader = new SeekableTextReader(document))
|
||||
using (var reader = new SeekableTextReader(document, filePath: null))
|
||||
{
|
||||
var context = new ParserContext(reader, designTime);
|
||||
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
|
||||
private IEnumerable<ISymbol> Tokenize(string content, bool markup)
|
||||
{
|
||||
var tokenizer = MakeTokenizer(markup, new SeekableTextReader(content));
|
||||
var tokenizer = MakeTokenizer(markup, new SeekableTextReader(content, filePath: null));
|
||||
ISymbol symbol;
|
||||
ISymbol last = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
private class ExposedTokenizer : Tokenizer<CSharpSymbol, CSharpSymbolType>
|
||||
{
|
||||
public ExposedTokenizer(string input)
|
||||
: base(new SeekableTextReader(input))
|
||||
: base(new SeekableTextReader(input, filePath: null))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
|
|||
// Arrange
|
||||
var success = true;
|
||||
var output = new StringBuilder();
|
||||
using (var source = new SeekableTextReader(input))
|
||||
using (var source = new SeekableTextReader(input, filePath: null))
|
||||
{
|
||||
var tokenizer = (Tokenizer<TSymbol, TSymbolType>)CreateTokenizer(source);
|
||||
var counter = 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// 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 Microsoft.AspNetCore.Razor.Evolution.Legacy;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Evolution.Test
|
||||
|
|
@ -20,5 +22,39 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Test
|
|||
Assert.NotNull(syntaxTree);
|
||||
Assert.Empty(syntaxTree.Diagnostics);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_Persists_FilePath()
|
||||
{
|
||||
// Arrange
|
||||
var filePath = "test.cshtml";
|
||||
var source = TestRazorSourceDocument.Create("@if (true) { @if(false) { <div>@something.</div> } }", fileName: filePath);
|
||||
|
||||
// Act
|
||||
var syntaxTree = RazorSyntaxTree.Parse(source);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(syntaxTree.Diagnostics);
|
||||
Assert.NotNull(syntaxTree);
|
||||
|
||||
var spans = new List<SyntaxTreeNode>();
|
||||
GetChildren(syntaxTree.Root);
|
||||
Assert.All(spans, node => Assert.Equal(filePath, node.Start.FilePath));
|
||||
|
||||
void GetChildren(SyntaxTreeNode node)
|
||||
{
|
||||
if (node is Block block)
|
||||
{
|
||||
foreach (var child in block.Children)
|
||||
{
|
||||
GetChildren(child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spans.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
@addTagHelper *, TestAssembly
|
||||
<form>
|
||||
<input value='Hello' type='text' />";
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content);
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
|
||||
var codeDocument = RazorCodeDocument.Create(sourceDocument);
|
||||
|
||||
var originalTree = RazorSyntaxTree.Parse(sourceDocument);
|
||||
|
|
@ -1334,7 +1334,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
<form>
|
||||
<input value='Hello' type='text' />
|
||||
</form>";
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content);
|
||||
var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null);
|
||||
return sourceDocument;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,14 +52,14 @@ namespace Microsoft.AspNetCore.Razor.Evolution
|
|||
return stream;
|
||||
}
|
||||
|
||||
public static RazorSourceDocument Create(string content = "Hello, world!", Encoding encoding = null, bool normalizeNewLines = false)
|
||||
public static RazorSourceDocument Create(string content = "Hello, world!", Encoding encoding = null, bool normalizeNewLines = false, string fileName = "test.cshtml")
|
||||
{
|
||||
if (normalizeNewLines)
|
||||
{
|
||||
content = NormalizeNewLines(content);
|
||||
}
|
||||
|
||||
return new TestRazorSourceDocument(content, encoding ?? Encoding.UTF8, "test.cshtml");
|
||||
return new TestRazorSourceDocument(content, encoding ?? Encoding.UTF8, fileName);
|
||||
}
|
||||
|
||||
private static string NormalizeNewLines(string content)
|
||||
|
|
|
|||
Loading…
Reference in New Issue