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.Html;
|
||||
using AngleSharp.Parser.Html;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
|
||||
using Microsoft.AspNetCore.Razor.Language.Intermediate;
|
||||
|
||||
|
|
@ -286,7 +287,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
{
|
||||
_scopeStack.CloseScope(
|
||||
tagName: isComponent ? tagNameOriginalCase : nextTag.Data,
|
||||
isComponent: isComponent);
|
||||
isComponent: isComponent,
|
||||
source: CalculateSourcePosition(node.Source, nextToken.Position));
|
||||
var closeMethodName = isComponent
|
||||
? nameof(RenderTreeBuilder.CloseComponent)
|
||||
: 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)
|
||||
{
|
||||
var offset = tagToken.Type == HtmlTokenType.EndTag ? 1 : 0; // For end tags, skip the '/'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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 Microsoft.AspNetCore.Razor.Language;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Blazor.Razor
|
||||
|
|
@ -11,16 +12,25 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
/// </summary>
|
||||
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)
|
||||
=> new RazorCompilerDiagnostic(
|
||||
RazorCompilerDiagnostic.DiagnosticType.Error,
|
||||
sourceFilePath,
|
||||
line: 1, // Later it might be necessary to take line/col constructor args, but not needed yet
|
||||
column: 1,
|
||||
line: _line,
|
||||
column: _column,
|
||||
message: Message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
_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)
|
||||
{
|
||||
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();
|
||||
if (!tagName.Equals(expected.TagName, StringComparison.Ordinal))
|
||||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -525,7 +525,14 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
{
|
||||
// Arrange/Act
|
||||
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.Collection(result.Diagnostics,
|
||||
|
|
@ -533,6 +540,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
{
|
||||
Assert.Equal(RazorCompilerDiagnostic.DiagnosticType.Error, item.Type);
|
||||
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