Report line/column when reporting mismatching tags
This commit is contained in:
parent
0665d30e19
commit
bd455453d6
|
|
@ -8,6 +8,7 @@ using System.Text;
|
||||||
using AngleSharp;
|
using AngleSharp;
|
||||||
using AngleSharp.Html;
|
using AngleSharp.Html;
|
||||||
using AngleSharp.Parser.Html;
|
using AngleSharp.Parser.Html;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||||
|
|
||||||
|
|
@ -286,7 +287,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
{
|
{
|
||||||
_scopeStack.CloseScope(
|
_scopeStack.CloseScope(
|
||||||
tagName: isComponent ? tagNameOriginalCase : nextTag.Data,
|
tagName: isComponent ? tagNameOriginalCase : nextTag.Data,
|
||||||
isComponent: isComponent);
|
isComponent: isComponent,
|
||||||
|
source: CalculateSourcePosition(node.Source, nextToken.Position));
|
||||||
var closeMethodName = isComponent
|
var closeMethodName = isComponent
|
||||||
? nameof(RenderTreeBuilder.CloseComponent)
|
? nameof(RenderTreeBuilder.CloseComponent)
|
||||||
: nameof(RenderTreeBuilder.CloseElement);
|
: nameof(RenderTreeBuilder.CloseElement);
|
||||||
|
|
@ -315,6 +317,28 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SourceSpan? CalculateSourcePosition(
|
||||||
|
SourceSpan? razorTokenPosition,
|
||||||
|
TextPosition htmlNodePosition)
|
||||||
|
{
|
||||||
|
if (razorTokenPosition.HasValue)
|
||||||
|
{
|
||||||
|
var razorPos = razorTokenPosition.Value;
|
||||||
|
return new SourceSpan(
|
||||||
|
razorPos.FilePath,
|
||||||
|
razorPos.AbsoluteIndex + htmlNodePosition.Position,
|
||||||
|
razorPos.LineIndex + htmlNodePosition.Line - 1,
|
||||||
|
htmlNodePosition.Line == 1
|
||||||
|
? razorPos.CharacterIndex + htmlNodePosition.Column - 1
|
||||||
|
: htmlNodePosition.Column - 1,
|
||||||
|
length: 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetTagNameWithOriginalCase(string document, HtmlTagToken tagToken)
|
private static string GetTagNameWithOriginalCase(string document, HtmlTagToken tagToken)
|
||||||
{
|
{
|
||||||
var offset = tagToken.Type == HtmlTokenType.EndTag ? 1 : 0; // For end tags, skip the '/'
|
var offset = tagToken.Type == HtmlTokenType.EndTag ? 1 : 0; // For end tags, skip the '/'
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Blazor.Razor
|
namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
|
|
@ -11,16 +12,25 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RazorCompilerException : Exception
|
public class RazorCompilerException : Exception
|
||||||
{
|
{
|
||||||
public RazorCompilerException(string message) : base(message)
|
private readonly int _line;
|
||||||
|
private readonly int _column;
|
||||||
|
|
||||||
|
public RazorCompilerException(string message) : this(message, null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RazorCompilerException(string message, SourceSpan? source) : base(message)
|
||||||
|
{
|
||||||
|
_line = source.HasValue ? (source.Value.LineIndex + 1) : 1;
|
||||||
|
_column = source.HasValue ? (source.Value.CharacterIndex + 1) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
public RazorCompilerDiagnostic ToDiagnostic(string sourceFilePath)
|
public RazorCompilerDiagnostic ToDiagnostic(string sourceFilePath)
|
||||||
=> new RazorCompilerDiagnostic(
|
=> new RazorCompilerDiagnostic(
|
||||||
RazorCompilerDiagnostic.DiagnosticType.Error,
|
RazorCompilerDiagnostic.DiagnosticType.Error,
|
||||||
sourceFilePath,
|
sourceFilePath,
|
||||||
line: 1, // Later it might be necessary to take line/col constructor args, but not needed yet
|
line: _line,
|
||||||
column: 1,
|
column: _column,
|
||||||
message: Message);
|
message: Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,19 +21,19 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
||||||
_stack.Push(new ScopeEntry(tagName, isComponent));
|
_stack.Push(new ScopeEntry(tagName, isComponent));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseScope(string tagName, bool isComponent)
|
public void CloseScope(string tagName, bool isComponent, SourceSpan? source)
|
||||||
{
|
{
|
||||||
if (_stack.Count == 0)
|
if (_stack.Count == 0)
|
||||||
{
|
{
|
||||||
throw new RazorCompilerException(
|
throw new RazorCompilerException(
|
||||||
$"Unexpected closing tag '{tagName}' with no matching start tag.");
|
$"Unexpected closing tag '{tagName}' with no matching start tag.", source);
|
||||||
}
|
}
|
||||||
|
|
||||||
var expected = _stack.Pop();
|
var expected = _stack.Pop();
|
||||||
if (!tagName.Equals(expected.TagName, StringComparison.Ordinal))
|
if (!tagName.Equals(expected.TagName, StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
throw new RazorCompilerException(
|
throw new RazorCompilerException(
|
||||||
$"Mismatching closing tag. Found '{tagName}' but expected '{expected.TagName}'.");
|
$"Mismatching closing tag. Found '{tagName}' but expected '{expected.TagName}'.", source);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: there's no unit test to cover the following, because there's no known way of
|
// Note: there's no unit test to cover the following, because there's no known way of
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,14 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
{
|
{
|
||||||
// Arrange/Act
|
// Arrange/Act
|
||||||
var result = CompileToCSharp(
|
var result = CompileToCSharp(
|
||||||
"<root><other />text<child>more text</root></child>");
|
$"@{{\n" +
|
||||||
|
$" var abc = 123;\n" +
|
||||||
|
$"}}\n" +
|
||||||
|
$"<root>\n" +
|
||||||
|
$" <other />\n" +
|
||||||
|
$" text\n" +
|
||||||
|
$" <child>more text</root>\n" +
|
||||||
|
$"</child>\n");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Diagnostics,
|
Assert.Collection(result.Diagnostics,
|
||||||
|
|
@ -533,6 +540,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
{
|
{
|
||||||
Assert.Equal(RazorCompilerDiagnostic.DiagnosticType.Error, item.Type);
|
Assert.Equal(RazorCompilerDiagnostic.DiagnosticType.Error, item.Type);
|
||||||
Assert.StartsWith("Mismatching closing tag. Found 'root' but expected 'child'.", item.Message);
|
Assert.StartsWith("Mismatching closing tag. Found 'root' but expected 'child'.", item.Message);
|
||||||
|
Assert.Equal(7, item.Line);
|
||||||
|
Assert.Equal(21, item.Column);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue