Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for GitHub style tables #111

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CommonMark.Tests/CommonMark.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<Compile Include="HtmlTests.cs" />
<Compile Include="SettingsTests.cs" />
<Compile Include="GeneralTests.cs" />
<Compile Include="TableTests.cs" />
<Compile Include="UrlTests.cs" />
<Compile Include="EmphasisTests.cs" />
<Compile Include="Helpers.cs" />
Expand Down
342 changes: 342 additions & 0 deletions CommonMark.Tests/TableTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
using CommonMark.Syntax;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;

namespace CommonMark.Tests
{
[TestClass]
public class TableTests
{
static CommonMarkSettings ReadSettings;
static CommonMarkSettings WriteSettings;

static TableTests()
{
ReadSettings = CommonMarkSettings.Default.Clone();
ReadSettings.AdditionalFeatures = CommonMarkAdditionalFeatures.GithubStyleTables;
ReadSettings.TrackSourcePosition = true;

WriteSettings = CommonMarkSettings.Default.Clone();
WriteSettings.AdditionalFeatures = CommonMarkAdditionalFeatures.GithubStyleTables;
}

[TestMethod]
public void SimpleTable()
{
var markdown = "First Header | Second Header\n------------- | -------------\nContent Cell | Content Cell\nContent Cell | Content Cell\n";

var ast =
CommonMarkConverter.Parse(
markdown,
ReadSettings
);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td>Content Cell</td><td>Content Cell</td></tr><tr><td>Content Cell</td><td>Content Cell</td></tr></tbody></table>", html);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would be better if every would be followed by a newline? Perhaps even each cell?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is according to the GHFM-specs, i think its better to leave it as is to have it the same as the spec.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, agree


var firstChild = ast.FirstChild;
Assert.AreEqual(BlockTag.Table, firstChild.Tag);
Assert.AreEqual(markdown, markdown.Substring(firstChild.SourcePosition, firstChild.SourceLength));
Assert.IsNotNull(firstChild.TableHeaderAlignments);
Assert.AreEqual(2, firstChild.TableHeaderAlignments.Length);
Assert.AreEqual(TableHeaderAlignment.None, firstChild.TableHeaderAlignments[0]);
Assert.AreEqual(TableHeaderAlignment.None, firstChild.TableHeaderAlignments[1]);

var headerRow = firstChild.FirstChild;
Assert.AreEqual(BlockTag.TableRow, headerRow.Tag);
Assert.AreEqual("First Header | Second Header\n", markdown.Substring(headerRow.SourcePosition, headerRow.SourceLength));

var headerCell1 = headerRow.FirstChild;
Assert.AreEqual(BlockTag.TableCell, headerCell1.Tag);
Assert.AreEqual("First Header", markdown.Substring(headerCell1.SourcePosition, headerCell1.SourceLength));

var headerCell2 = headerCell1.NextSibling;
Assert.AreEqual(BlockTag.TableCell, headerCell2.Tag);
Assert.AreEqual("Second Header", markdown.Substring(headerCell2.SourcePosition, headerCell2.SourceLength));
Assert.IsNull(headerCell2.NextSibling);

var firstRow = headerRow.NextSibling;
Assert.AreEqual(BlockTag.TableRow, firstRow.Tag);
Assert.AreEqual("Content Cell | Content Cell\n", markdown.Substring(firstRow.SourcePosition, firstRow.SourceLength));

var firstRowCell1 = firstRow.FirstChild;
Assert.AreEqual(BlockTag.TableCell, firstRowCell1.Tag);
Assert.AreEqual("Content Cell", markdown.Substring(firstRowCell1.SourcePosition, firstRowCell1.SourceLength));

var firstRowCell2 = firstRowCell1.NextSibling;
Assert.AreEqual(BlockTag.TableCell, firstRowCell2.Tag);
Assert.AreEqual("Content Cell", markdown.Substring(firstRowCell2.SourcePosition, firstRowCell2.SourceLength));
Assert.IsNull(firstRowCell2.NextSibling);

var secondRow = firstRow.NextSibling;
Assert.AreEqual(BlockTag.TableRow, secondRow.Tag);
Assert.AreEqual("Content Cell | Content Cell\n", markdown.Substring(secondRow.SourcePosition, secondRow.SourceLength));
Assert.IsNull(secondRow.NextSibling);

var secondRowCell1 = secondRow.FirstChild;
Assert.AreEqual(BlockTag.TableCell, secondRowCell1.Tag);
Assert.AreEqual("Content Cell", markdown.Substring(secondRowCell1.SourcePosition, secondRowCell1.SourceLength));

var secondRowCell2 = secondRowCell1.NextSibling;
Assert.AreEqual(BlockTag.TableCell, secondRowCell2.Tag);
Assert.AreEqual("Content Cell", markdown.Substring(secondRowCell2.SourcePosition, secondRowCell2.SourceLength));
Assert.IsNull(secondRowCell2.NextSibling);
}

[TestMethod]
public void WrappedTable()
{
var markdown =
@"Nope nope.

First Header | Second Header
------------- | -------------
Content Cell | Content Cell
Content Cell | Content Cell
Hello world
";

var ast =
CommonMarkConverter.Parse(
markdown,
ReadSettings
);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
string expected = "<p>Nope nope.</p>\r\n<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td>Content Cell</td><td>Content Cell</td></tr><tr><td>Content Cell</td><td>Content Cell</td></tr><tr><td>Hello world</td><td></td></tr></tbody></table>";

Assert.AreEqual(expected, html);

Assert.AreEqual(BlockTag.Paragraph, ast.FirstChild.Tag);
Assert.AreEqual(BlockTag.Table, ast.FirstChild.NextSibling.Tag);
}

[TestMethod]
public void TableWithInlines()
{
var markdown =
@" Name | Description
------------- | -----------
Help | **Display the** [help](/help) window.
Close | _Closes_ a window ";

var ast =
CommonMarkConverter.Parse(
markdown,
ReadSettings
);
string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>Name</th><th>Description</th></tr></thead><tbody><tr><td>Help</td><td><strong>Display the</strong> <a href=\"/help\">help</a> window.</td></tr><tr><td>Close</td><td><em>Closes</em> a window</td></tr></tbody></table>", html);
}

[TestMethod]
public void TableCellMismatch()
{
var markdown =
@"| First Header | Second Header |
| ------------- | ------------- |
| 11 |
| 21 | 22 | 23
";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);
string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td>11</td><td></td></tr><tr><td>21</td><td>22</td></tr></tbody></table>", html);
}

[TestMethod]
public void TableAlignment()
{
var markdown =
@"| H1 | H2 | H3 | H4
--- | :-- | ---:| :-: |
|1|2|3|4|
";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);
var table = ast.FirstChild;
Assert.AreEqual(BlockTag.Table, table.Tag);
Assert.AreEqual(4, table.TableHeaderAlignments.Length);
Assert.AreEqual(TableHeaderAlignment.None, table.TableHeaderAlignments[0]);
Assert.AreEqual(TableHeaderAlignment.Left, table.TableHeaderAlignments[1]);
Assert.AreEqual(TableHeaderAlignment.Right, table.TableHeaderAlignments[2]);
Assert.AreEqual(TableHeaderAlignment.Center, table.TableHeaderAlignments[3]);
string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>H1</th><th align=\"left\">H2</th><th align=\"right\">H3</th><th align=\"center\">H4</th></tr></thead><tbody><tr><td>1</td><td align=\"left\">2</td><td align=\"right\">3</td><td align=\"center\">4</td></tr></tbody></table>", html);
}


[TestMethod]
public void Example189()
{
var markdown = @"| foo | bar |
| --- | --- |
| baz | bim | ";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>foo</th><th>bar</th></tr></thead><tbody><tr><td>baz</td><td>bim</td></tr></tbody></table>", html);
}

[TestMethod]
public void Example190()
{
var markdown = @"| abc | defghi |
:-: | -----------:
bar | baz";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th align=\"center\">abc</th><th align=\"right\">defghi</th></tr></thead><tbody><tr><td align=\"center\">bar</td><td align=\"right\">baz</td></tr></tbody></table>", html);
}

[TestMethod]
public void Example191()
{
var markdown = @"| f\|oo |
| ------ |
| b `|` az |
| b **|** im |";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>f|oo</th></tr></thead><tbody><tr><td>b <code>|</code> az</td></tr><tr><td>b <strong>|</strong> im</td></tr></tbody></table>", html);
}

[TestMethod]
public void Example192()
{
var markdown = @"| abc | def |
| --- | --- |
| bar | baz |
> bar";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}

string expected = @"<table><thead><tr><th>abc</th><th>def</th></tr></thead><tbody><tr><td>bar</td><td>baz</td></tr></tbody></table>
<blockquote>
<p>bar</p>
</blockquote>
";

Assert.AreEqual(expected, html);
}

[TestMethod]
public void Example193()
{
var markdown = @"| abc | def |
| --- | --- |
| bar | baz |
bar

bar";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}

string expected = @"<table><thead><tr><th>abc</th><th>def</th></tr></thead><tbody><tr><td>bar</td><td>baz</td></tr><tr><td>bar</td><td></td></tr></tbody></table>
<p>bar</p>
";


Assert.AreEqual(expected, html);
}

[TestMethod]
public void Example194()
{
var markdown = @"| abc | def |
| --- |
| bar |";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual(@"<p>| abc | def |
| --- |
| bar |</p>
", html);
}

[TestMethod]
public void Example195()
{
var markdown = @"| abc | def |
| --- | --- |
| bar |
| bar | baz | boo |";

var ast = CommonMarkConverter.Parse(markdown, ReadSettings);

string html;
using (var str = new StringWriter())
{
CommonMarkConverter.ProcessStage3(ast, str, WriteSettings);
html = str.ToString();
}
Assert.AreEqual("<table><thead><tr><th>abc</th><th>def</th></tr></thead><tbody><tr><td>bar</td><td></td></tr><tr><td>bar</td><td>baz</td></tr></tbody></table>", html);
}
}
}
2 changes: 2 additions & 0 deletions CommonMark/CommonMark.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<Compile Include="Parser\PositionTracker.cs" />
<Compile Include="Parser\ScannerCharacterMatcher.cs" />
<Compile Include="Parser\ScannerHtmlTag.cs" />
<Compile Include="Parser\TableMethods.cs" />
<Compile Include="Parser\TabTextReader.cs" />
<Compile Include="Syntax\Block.cs" />
<Compile Include="Parser\BlockMethods.cs" />
Expand Down Expand Up @@ -86,6 +87,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Syntax\StringContent.cs" />
<Compile Include="Syntax\StringContentPart.cs" />
<Compile Include="Syntax\TableHeaderAlignment.cs" />
<Compile Include="Utilities.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions CommonMark/CommonMark.NET35.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<ProjectGuid>{61829669-5091-4F2A-A0B1-7348D7CED840}</ProjectGuid>
<TargetFrameworkVersionEx>v3.5</TargetFrameworkVersionEx>
<TargetFrameworkProfileEx>Client</TargetFrameworkProfileEx>
<DefineConstantsEx>OptimizeFor35</DefineConstantsEx>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
Expand Down
Loading