diff --git a/src/DocNet/Config.cs b/src/DocNet/Config.cs
index 2ff4195..2907117 100644
--- a/src/DocNet/Config.cs
+++ b/src/DocNet/Config.cs
@@ -216,6 +216,14 @@ namespace Docnet
}
}
+ public int MaxLevelInToC
+ {
+ get
+ {
+ return _configData.MaxLevelInToC ?? 2;
+ }
+ }
+
public string ThemeName
{
get
diff --git a/src/DocNet/INavigationElement.cs b/src/DocNet/INavigationElement.cs
index 0e97aac..12a4695 100644
--- a/src/DocNet/INavigationElement.cs
+++ b/src/DocNet/INavigationElement.cs
@@ -43,8 +43,9 @@ namespace Docnet
///
/// The navigated path to the current element, which doesn't necessarily have to be this element.
/// The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.
+ /// The maximum level.
///
- string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot);
+ string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, int maxLevel);
///
/// Collects the search index entries. These are created from simple navigation elements found in this container, which aren't index element.
///
diff --git a/src/DocNet/NavigatedPath.cs b/src/DocNet/NavigatedPath.cs
index b53f6c1..e08e76e 100644
--- a/src/DocNet/NavigatedPath.cs
+++ b/src/DocNet/NavigatedPath.cs
@@ -73,11 +73,12 @@ namespace Docnet
///
/// Creates the ToC HTML for the element reached by the elements in this path. All containers in this path are expanded, all elements inside these containers which
- /// aren't, are not expanded.
+ /// aren't, are not expanded.
///
/// The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.
+ /// The maximum level.
///
- public string CreateToCHTML(string relativePathToRoot)
+ public string CreateToCHTML(string relativePathToRoot, int maxLevel)
{
// the root container is the bottom element of this path. We use that container to build the root and navigate any node open along the navigated path.
var rootContainer = this.Reverse().FirstOrDefault() as NavigationLevel;
@@ -86,7 +87,7 @@ namespace Docnet
// no root container, no TOC
return string.Empty;
}
- return rootContainer.GenerateToCFragment(this, relativePathToRoot);
+ return rootContainer.GenerateToCFragment(this, relativePathToRoot, maxLevel);
}
}
}
diff --git a/src/DocNet/NavigationElement.cs b/src/DocNet/NavigationElement.cs
index dd86175..4a26709 100644
--- a/src/DocNet/NavigationElement.cs
+++ b/src/DocNet/NavigationElement.cs
@@ -43,8 +43,9 @@ namespace Docnet
///
/// The navigated path to the current element, which doesn't necessarily have to be this element.
/// The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.
+ /// The maximum level.
///
- public abstract string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot);
+ public abstract string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, int maxLevel);
///
/// Collects the search index entries. These are created from simple navigation elements found in this container, which aren't index element.
///
diff --git a/src/DocNet/NavigationLevel.cs b/src/DocNet/NavigationLevel.cs
index 57bc38b..3b29373 100644
--- a/src/DocNet/NavigationLevel.cs
+++ b/src/DocNet/NavigationLevel.cs
@@ -106,8 +106,9 @@ namespace Docnet
///
/// The navigated path to the current element, which doesn't necessarily have to be this element.
/// The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.
+ /// The maximum level.
///
- public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot)
+ public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, int maxLevel)
{
var fragments = new List();
if(!this.IsRoot)
@@ -138,7 +139,7 @@ namespace Docnet
{
if(this.IsRoot)
{
- fragments.Add(indexElement.PerformGenerateToCFragment(navigatedPath, relativePathToRoot));
+ fragments.Add(indexElement.PerformGenerateToCFragment(navigatedPath, relativePathToRoot, maxLevel));
}
else
{
@@ -149,7 +150,7 @@ namespace Docnet
// then the elements in the container. Index elements are skipped here.
foreach(var element in this.Value)
{
- fragments.Add(element.GenerateToCFragment(navigatedPath, relativePathToRoot));
+ fragments.Add(element.GenerateToCFragment(navigatedPath, relativePathToRoot, maxLevel));
}
fragments.Add("");
}
diff --git a/src/DocNet/SimpleNavigationElement.cs b/src/DocNet/SimpleNavigationElement.cs
index c47f2b7..6ecf0bd 100644
--- a/src/DocNet/SimpleNavigationElement.cs
+++ b/src/DocNet/SimpleNavigationElement.cs
@@ -27,6 +27,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
+using MarkdownDeep;
namespace Docnet
{
@@ -34,13 +35,14 @@ namespace Docnet
{
#region Members
private string _targetURLForHTML;
- private List> _relativeH2LinksOnPage; // first element in Tuple is anchor name, second is name for ToC.
+
+ private readonly List _relativeLinksOnPage; // first element in Tuple is anchor name, second is name for ToC.
#endregion
public SimpleNavigationElement()
{
- _relativeH2LinksOnPage = new List>();
+ _relativeLinksOnPage = new List();
}
@@ -52,50 +54,50 @@ namespace Docnet
public override void GenerateOutput(Config activeConfig, NavigatedPath activePath)
{
// if we're the __index element, we're not pushing ourselves on the path, as we're representing the container we're in, which is already on the path.
- if(!this.IsIndexElement)
+ if (!this.IsIndexElement)
{
activePath.Push(this);
}
- _relativeH2LinksOnPage.Clear();
+ _relativeLinksOnPage.Clear();
var sourceFile = Utils.MakeAbsolutePath(activeConfig.Source, this.Value);
var destinationFile = Utils.MakeAbsolutePath(activeConfig.Destination, this.TargetURL);
var sb = new StringBuilder(activeConfig.PageTemplateContents.Length + 2048);
var content = string.Empty;
this.MarkdownFromFile = string.Empty;
var relativePathToRoot = Utils.MakeRelativePathForUri(Path.GetDirectoryName(destinationFile), activeConfig.Destination);
- if(File.Exists(sourceFile))
+ if (File.Exists(sourceFile))
{
this.MarkdownFromFile = File.ReadAllText(sourceFile, Encoding.UTF8);
// Check if the content contains @@include tag
content = Utils.IncludeProcessor(this.MarkdownFromFile, Utils.MakeAbsolutePath(activeConfig.Source, activeConfig.IncludeFolder));
- content = Utils.ConvertMarkdownToHtml(content, Path.GetDirectoryName(destinationFile), activeConfig.Destination, sourceFile, _relativeH2LinksOnPage, activeConfig.ConvertLocalLinks);
+ content = Utils.ConvertMarkdownToHtml(content, Path.GetDirectoryName(destinationFile), activeConfig.Destination, sourceFile, _relativeLinksOnPage, activeConfig.ConvertLocalLinks);
}
else
{
// if we're not the index element, the file is missing and potentially it's an error in the config page.
// Otherwise we can simply assume we are a missing index page and we'll generate default markdown so the user has something to look at.
- if(this.IsIndexElement)
+ if (this.IsIndexElement)
{
// replace with default markdown snippet. This is the name of our container and links to the elements in that container as we are the index page that's not
// specified / existend.
var defaultMarkdown = new StringBuilder();
defaultMarkdown.AppendFormat("# {0}{1}{1}", this.ParentContainer.Name, Environment.NewLine);
defaultMarkdown.AppendFormat("Please select one of the topics in this section:{0}{0}", Environment.NewLine);
- foreach(var sibling in this.ParentContainer.Value)
+ foreach (var sibling in this.ParentContainer.Value)
{
- if(sibling == this)
+ if (sibling == this)
{
continue;
}
defaultMarkdown.AppendFormat("* [{0}]({1}{2}){3}", sibling.Name, relativePathToRoot, HttpUtility.UrlPathEncode(sibling.TargetURL), Environment.NewLine);
}
defaultMarkdown.Append(Environment.NewLine);
- content = Utils.ConvertMarkdownToHtml(defaultMarkdown.ToString(), Path.GetDirectoryName(destinationFile), activeConfig.Destination, string.Empty, _relativeH2LinksOnPage, activeConfig.ConvertLocalLinks);
+ content = Utils.ConvertMarkdownToHtml(defaultMarkdown.ToString(), Path.GetDirectoryName(destinationFile), activeConfig.Destination, string.Empty, _relativeLinksOnPage, activeConfig.ConvertLocalLinks);
}
else
{
// target not found. See if there's a content producer func to produce html for us. If not, we can only conclude an error in the config file.
- if(this.ContentProducerFunc == null)
+ if (this.ContentProducerFunc == null)
{
throw new FileNotFoundException(string.Format("The specified markdown file '{0}' couldn't be found. Aborting", sourceFile));
}
@@ -107,17 +109,17 @@ namespace Docnet
sb.Replace("{{Footer}}", activeConfig.Footer);
sb.Replace("{{TopicTitle}}", this.Name);
sb.Replace("{{Path}}", relativePathToRoot);
- sb.Replace("{{RelativeSourceFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, sourceFile).TrimEnd('/'));
- sb.Replace("{{RelativeTargetFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, destinationFile).TrimEnd('/'));
- sb.Replace("{{Breadcrumbs}}", activePath.CreateBreadCrumbsHTML(relativePathToRoot));
- sb.Replace("{{ToC}}", activePath.CreateToCHTML(relativePathToRoot));
+ sb.Replace("{{RelativeSourceFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, sourceFile).TrimEnd('/'));
+ sb.Replace("{{RelativeTargetFileName}}", Utils.MakeRelativePathForUri(activeConfig.Destination, destinationFile).TrimEnd('/'));
+ sb.Replace("{{Breadcrumbs}}", activePath.CreateBreadCrumbsHTML(relativePathToRoot));
+ sb.Replace("{{ToC}}", activePath.CreateToCHTML(relativePathToRoot, activeConfig.MaxLevelInToC));
sb.Replace("{{ExtraScript}}", (this.ExtraScriptProducerFunc == null) ? string.Empty : this.ExtraScriptProducerFunc(this));
// the last action has to be replacing the content marker, so markers in the content which we have in the template as well aren't replaced
sb.Replace("{{Content}}", content);
Utils.CreateFoldersIfRequired(destinationFile);
File.WriteAllText(destinationFile, sb.ToString());
- if(!this.IsIndexElement)
+ if (!this.IsIndexElement)
{
activePath.Pop();
}
@@ -133,7 +135,7 @@ namespace Docnet
{
activePath.Push(this);
// simply convert ourselves into an entry if we're not an index
- if(!this.IsIndexElement)
+ if (!this.IsIndexElement)
{
var toAdd = new SearchIndexEntry();
toAdd.Fill(this.MarkdownFromFile, this.TargetURL, this.Name, activePath);
@@ -148,16 +150,17 @@ namespace Docnet
///
/// The navigated path to the current element, which doesn't necessarily have to be this element.
/// The relative path back to the URL root, e.g. ../.., so it can be used for links to elements in this path.
+ /// The maximum level.
///
- public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot)
+ public override string GenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, int maxLevel)
{
// index elements are rendered in the parent container.
- if(this.IsIndexElement)
+ if (this.IsIndexElement)
{
return string.Empty;
}
- return PerformGenerateToCFragment(navigatedPath, relativePathToRoot);
+ return PerformGenerateToCFragment(navigatedPath, relativePathToRoot, maxLevel, null);
}
@@ -167,15 +170,17 @@ namespace Docnet
///
/// The navigated path.
/// The relative path to root.
+ /// The maximum level.
+ /// The parent heading.
///
- public string PerformGenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot)
+ public string PerformGenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, int maxLevel)
{
// we can't navigate deeper from here. If we are the element being navigated to, we are the current and will have to emit any additional relative URLs too.
bool isCurrent = navigatedPath.Contains(this);
var fragments = new List();
var liClass = "tocentry";
var aClass = string.Empty;
- if(isCurrent)
+ if (isCurrent)
{
liClass = "tocentry current";
aClass = "current";
@@ -186,20 +191,46 @@ namespace Docnet
relativePathToRoot,
HttpUtility.UrlPathEncode(this.TargetURL),
this.Name));
- if(isCurrent && _relativeH2LinksOnPage.Any())
+
+ if (isCurrent)
{
- // generate relative links
- fragments.Add(string.Format("", this.ParentContainer.IsRoot ? "currentrelativeroot" : "currentrelative"));
- foreach(var p in _relativeH2LinksOnPage)
+ var content = PerformGenerateToCFragment(navigatedPath, relativePathToRoot, maxLevel, null);
+ if (!string.IsNullOrWhiteSpace(content))
{
- fragments.Add(string.Format("- {1}
", p.Item1, p.Item2));
+ fragments.Add(content);
}
- fragments.Add("
");
}
- else
+
+ fragments.Add("");
+
+ return string.Join(Environment.NewLine, fragments.ToArray());
+ }
+
+ private string PerformGenerateToCFragment(NavigatedPath navigatedPath, string relativePathToRoot, int maxLevel, Heading parentHeading)
+ {
+ var fragments = new List();
+
+ var headings = (parentHeading != null) ? parentHeading.Children : _relativeLinksOnPage;
+ var includedHeadings = headings.Where(x => x.Level > 1 && x.Level <= maxLevel).ToList();
+ if (includedHeadings.Count > 0)
{
- fragments.Add("");
+ fragments.Add(string.Format("", this.ParentContainer.IsRoot ? "currentrelativeroot" : "currentrelative"));
+
+ // generate relative links
+ foreach (var heading in includedHeadings)
+ {
+ fragments.Add(string.Format("- {1}
", heading.Id, heading.Name));
+
+ var headingContent = PerformGenerateToCFragment(navigatedPath, relativePathToRoot, maxLevel, heading);
+ if (!string.IsNullOrWhiteSpace(headingContent))
+ {
+ fragments.Add(headingContent);
+ }
+ }
+
+ fragments.Add("
");
}
+
return string.Join(Environment.NewLine, fragments.ToArray());
}
@@ -209,12 +240,12 @@ namespace Docnet
{
get
{
- if(_targetURLForHTML==null)
+ if (_targetURLForHTML == null)
{
_targetURLForHTML = (this.Value ?? string.Empty);
- if(_targetURLForHTML.ToLowerInvariant().EndsWith(".md"))
+ if (_targetURLForHTML.ToLowerInvariant().EndsWith(".md"))
{
- _targetURLForHTML = _targetURLForHTML.Substring(0, _targetURLForHTML.Length-3) + ".htm";
+ _targetURLForHTML = _targetURLForHTML.Substring(0, _targetURLForHTML.Length - 3) + ".htm";
}
_targetURLForHTML = _targetURLForHTML.Replace("\\", "/");
}
diff --git a/src/DocNet/Utils.cs b/src/DocNet/Utils.cs
index d5becc3..1aefc4e 100644
--- a/src/DocNet/Utils.cs
+++ b/src/DocNet/Utils.cs
@@ -27,6 +27,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using MarkdownDeep;
namespace Docnet
{
@@ -50,7 +51,7 @@ namespace Docnet
/// if set to true, convert local links to md files to target files.
///
public static string ConvertMarkdownToHtml(string toConvert, string destinationDocumentPath, string siteRoot, string sourceDocumentFilename,
- List> createdAnchorCollector, bool convertLocalLinks)
+ List createdAnchorCollector, bool convertLocalLinks)
{
var parser = new MarkdownDeep.Markdown
{
@@ -67,7 +68,9 @@ namespace Docnet
};
var toReturn = parser.Transform(toConvert);
- createdAnchorCollector.AddRange(parser.CreatedH2IdCollector);
+
+ createdAnchorCollector.AddRange(parser.Headings.ConvertToHierarchy());
+
return toReturn;
}
diff --git a/src/MarkdownDeep/Block.cs b/src/MarkdownDeep/Block.cs
index 4df2802..08fb719 100644
--- a/src/MarkdownDeep/Block.cs
+++ b/src/MarkdownDeep/Block.cs
@@ -193,14 +193,19 @@ namespace MarkdownDeep
{
b.Append("<" + BlockType.ToString() + ">");
}
- if(m.DocNetMode && BlockType == BlockType.h2 && !string.IsNullOrWhiteSpace(id))
+ if(m.DocNetMode && !string.IsNullOrWhiteSpace(id))
{
- // collect h2 id + text in collector
- var h2ContentSb = new StringBuilder();
- m.SpanFormatter.Format(h2ContentSb, Buf, ContentStart, ContentLen);
- var h2ContentAsString = h2ContentSb.ToString();
- b.Append(h2ContentAsString);
- m.CreatedH2IdCollector.Add(new Tuple(id, h2ContentAsString));
+ // collect id + text in collector
+ var headerContentStringBuilder = new StringBuilder();
+ m.SpanFormatter.Format(headerContentStringBuilder, Buf, ContentStart, ContentLen);
+ var headerContentAsString = headerContentStringBuilder.ToString();
+ b.Append(headerContentAsString);
+ m.Headings.Add(new Heading
+ {
+ Level = (int)BlockType,
+ Id = id,
+ Name = headerContentAsString
+ });
}
else
{
diff --git a/src/MarkdownDeep/Extensions.cs b/src/MarkdownDeep/Extensions.cs
new file mode 100644
index 0000000..4901e42
--- /dev/null
+++ b/src/MarkdownDeep/Extensions.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+
+namespace MarkdownDeep
+{
+ public static class Extensions
+ {
+ public static List ConvertToHierarchy(this List headings)
+ {
+ var hierarchy = new List();
+
+ for (var i = 0; i < headings.Count; i++)
+ {
+ if (i > 0)
+ {
+ var previousHeading = headings[i - 1];
+ var currentHeading = headings[i];
+
+ SetParentForHeading(previousHeading, currentHeading);
+
+ var parent = currentHeading.Parent;
+ if (parent == null)
+ {
+ hierarchy.Add(currentHeading);
+ }
+ else
+ {
+ parent.Children.Add(currentHeading);
+ }
+ }
+ else
+ {
+ hierarchy.Add(headings[i]);
+ }
+ }
+
+ return hierarchy;
+ }
+
+ private static void SetParentForHeading(Heading previousHeading, Heading headingToAdd)
+ {
+ if (previousHeading.Level == headingToAdd.Level)
+ {
+ headingToAdd.Parent = previousHeading.Parent;
+ }
+ else if (previousHeading.Level < headingToAdd.Level)
+ {
+ headingToAdd.Parent = previousHeading;
+ }
+ else if (previousHeading.Level > headingToAdd.Level)
+ {
+ var previousHeadingParent = previousHeading.Parent;
+ if (previousHeadingParent != null)
+ {
+ SetParentForHeading(previousHeadingParent, headingToAdd);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MarkdownDeep/Heading.cs b/src/MarkdownDeep/Heading.cs
new file mode 100644
index 0000000..6ff8814
--- /dev/null
+++ b/src/MarkdownDeep/Heading.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace MarkdownDeep
+{
+ public class Heading
+ {
+ public Heading()
+ {
+ Children = new List();
+ }
+
+ public Heading Parent { get; set; }
+
+ public List Children { get; private set; }
+
+ public int Level { get; set; }
+
+ public string Id { get; set; }
+
+ public string Name { get; set; }
+
+ public override string ToString()
+ {
+ var stringBuilder = new StringBuilder();
+
+ for (var i = 0; i < Level; i++)
+ {
+ stringBuilder.Append("#");
+ }
+
+ stringBuilder.AppendLine($"{Id} - {Name}");
+
+ foreach (var child in Children)
+ {
+ stringBuilder.AppendLine(child.ToString());
+ }
+
+ var value = stringBuilder.ToString();
+ return value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MarkdownDeep/MardownDeep.cs b/src/MarkdownDeep/MardownDeep.cs
index 9b496fe..0e2eaa9 100644
--- a/src/MarkdownDeep/MardownDeep.cs
+++ b/src/MarkdownDeep/MardownDeep.cs
@@ -57,7 +57,9 @@ namespace MarkdownDeep
m_Footnotes = new Dictionary();
m_UsedFootnotes = new List();
m_UsedHeaderIDs = new Dictionary();
- this.CreatedH2IdCollector = new List>();
+
+ this.Headings = new List();
+
_tabIdCounter = 0;
}
@@ -951,13 +953,11 @@ namespace MarkdownDeep
set;
}
-
///
- /// Collector for the created id's for H2 headers. First element in Tuple is id name, second is name for ToC (the text for H2). Id's are generated
+ /// Collector for the created id's for headers. First element in Tuple is id name, second is name for ToC (the text for header). Id's are generated
/// by the parser and use pandoc algorithm, as AutoHeadingId's is switched on. Only in use if DocNetMode is set to true
///
- public List> CreatedH2IdCollector { get; private set; }
-
+ public List Headings { get; private set; }
// Set the html class for the footnotes div
// (defaults to "footnotes")
diff --git a/src/MarkdownDeep/MarkdownDeep.csproj b/src/MarkdownDeep/MarkdownDeep.csproj
index 15dce5a..9cec4eb 100644
--- a/src/MarkdownDeep/MarkdownDeep.csproj
+++ b/src/MarkdownDeep/MarkdownDeep.csproj
@@ -77,7 +77,9 @@
+
+
diff --git a/src/MarkdownDeepTests/ExtensionsTests.cs b/src/MarkdownDeepTests/ExtensionsTests.cs
new file mode 100644
index 0000000..601e5d8
--- /dev/null
+++ b/src/MarkdownDeepTests/ExtensionsTests.cs
@@ -0,0 +1,65 @@
+using System.Collections.Generic;
+using MarkdownDeep;
+using NUnit.Framework;
+
+namespace MarkdownDeepTests
+{
+ [TestFixture]
+ public class ExtensionsTests
+ {
+ [TestCase]
+ public void ConvertsHeadingsHierarchy()
+ {
+ var headings = new List();
+ headings.Add(new Heading { Level = 1, Name = "1" });
+ headings.Add(new Heading { Level = 2, Name = "1.1" });
+ headings.Add(new Heading { Level = 3, Name = "1.1.1" });
+ headings.Add(new Heading { Level = 2, Name = "1.2" });
+ headings.Add(new Heading { Level = 4, Name = "1.2.1.1" });
+ headings.Add(new Heading { Level = 2, Name = "1.3" });
+ headings.Add(new Heading { Level = 1, Name = "2" });
+ headings.Add(new Heading { Level = 3, Name = "2.1.1" });
+ headings.Add(new Heading { Level = 2, Name = "2.2" });
+
+ var hierarchy = headings.ConvertToHierarchy();
+
+ Assert.AreEqual(2, hierarchy.Count);
+
+ var heading1 = hierarchy[0];
+ Assert.AreEqual("1", heading1.Name);
+ Assert.AreEqual(3, heading1.Children.Count);
+
+ var heading1_1 = heading1.Children[0];
+ Assert.AreEqual("1.1", heading1_1.Name);
+ Assert.AreEqual(1, heading1_1.Children.Count);
+
+ var heading1_1_1 = heading1_1.Children[0];
+ Assert.AreEqual("1.1.1", heading1_1_1.Name);
+ Assert.AreEqual(0, heading1_1_1.Children.Count);
+
+ var heading1_2 = heading1.Children[1];
+ Assert.AreEqual("1.2", heading1_2.Name);
+ Assert.AreEqual(1, heading1_2.Children.Count);
+
+ var heading1_2_1_1 = heading1_2.Children[0];
+ Assert.AreEqual("1.2.1.1", heading1_2_1_1.Name);
+ Assert.AreEqual(0, heading1_2_1_1.Children.Count);
+
+ var heading1_3 = heading1.Children[2];
+ Assert.AreEqual("1.3", heading1_3.Name);
+ Assert.AreEqual(0, heading1_3.Children.Count);
+
+ var heading2 = hierarchy[1];
+ Assert.AreEqual("2", heading2.Name);
+ Assert.AreEqual(2, heading2.Children.Count);
+
+ var heading2_1_1 = heading2.Children[0];
+ Assert.AreEqual("2.1.1", heading2_1_1.Name);
+ Assert.AreEqual(0, heading2_1_1.Children.Count);
+
+ var heading2_2 = heading2.Children[1];
+ Assert.AreEqual("2.2", heading2_2.Name);
+ Assert.AreEqual(0, heading2_2.Children.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MarkdownDeepTests/MarkdownDeepTests.csproj b/src/MarkdownDeepTests/MarkdownDeepTests.csproj
index 21def54..d3512f9 100644
--- a/src/MarkdownDeepTests/MarkdownDeepTests.csproj
+++ b/src/MarkdownDeepTests/MarkdownDeepTests.csproj
@@ -75,6 +75,7 @@
+