Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<PropertyGroup>
<NoWarn>CS1591;CS0649;NU1608;NU1109</NoWarn>
<Version>5.1.1</Version>
<Version>5.1.2</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<LangVersion>preview</LangVersion>
<PackageTags>AngleSharp, Verify</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>My first paragraph.</p>
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@

<p>My first paragraph.</p>
<p>My first paragraph.</p>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

<div>
<div>
<pre>SELECT [e].[Name]
FROM [Employees] AS [e]
WHERE [e].[Active] = 1</pre>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

<div>
<div>
<textarea>line one
line two</textarea>
<script>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@

<td>Aaron</td>
<td>Aaron</td>
<td>FullTime</td>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

<!--marker-->
<!--marker-->
<thead>
<tr>
<th>Name</th>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

<tr>
<tr>
<td>Aaron</td>
<td>FullTime</td>
</tr>
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

<thead>
<thead>
<tr>
<th>Name</th>
</tr>
Expand Down
30 changes: 30 additions & 0 deletions src/Tests/PrettyPrintHtmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,34 @@ public Task FragmentOpeningWithText()
return Verify(html, "html")
.PrettyPrintHtml();
}

// A fragment is parsed against a context element that is never written, and the formatter breaks
// the line before every node inside an element. So the first node took a break with nothing in
// front of it and the markup opened on the second line.
//
// Compared as text rather than by the registered html comparer: that one diffs the two DOMs, where
// a blank line before the first node is whitespace between nodes and no difference at all. Every
// other test here is blind to the thing this one is for.
[Test]
public Task FragmentDoesNotOpenWithABlankLine()
{
var html = "<p>My first paragraph.</p>";
return Verify(html, "html")
.PrettyPrintHtml()
.UseStringComparer(CompareText);
}

static Task<VerifyTests.CompareResult> CompareText(
string received,
string verified,
IReadOnlyDictionary<string, object> context)
{
if (string.Equals(received, verified, StringComparison.Ordinal))
{
return Task.FromResult(VerifyTests.CompareResult.Equal);
}

return Task.FromResult(
VerifyTests.CompareResult.NotEqual($"Received:{Environment.NewLine}{received}"));
}
}
18 changes: 18 additions & 0 deletions src/Verify.AngleSharp/HtmlPrettyPrint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -313,12 +313,30 @@ static void CleanSource(StringBuilder builder, Action<INodeList>? action)
document.ToHtml(writer, formatter);
}

TrimLeadingNewLine(builder);

for (var index = 0; index < preserved.Count; index++)
{
builder.Replace(Placeholder(index), preserved[index]);
}
}

/// <summary>
/// The formatter breaks the line before every node that sits inside an element, to part it from
/// whatever came before. A fragment is parsed against a context element that is never itself
/// written, so its first node takes that break with nothing in front of it and the markup opens on
/// the second line. A document has no such context, and a fragment opening with text is not broken
/// before either, so in those cases there is nothing here to remove.
/// </summary>
static void TrimLeadingNewLine(StringBuilder builder)
{
if (builder.Length > 0 &&
builder[0] == '\n')
{
builder.Remove(0, 1);
}
}

/// <summary>
/// Swaps the content of each preformatted element for a placeholder, returning the markup each
/// stood for. The element keeps its place, so the document is laid out exactly as it would have
Expand Down
Loading