public Task WithSpaces()
    {
        var lines = new List <Line>
        {
            new Line("##  A B ", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 1, new List <string>(), Environment.NewLine)));
    }
    public Task StripMarkdown()
    {
        var lines = new List <Line>
        {
            new Line("## **bold** *italic* [Link](link)", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 1, new List <string>(), Environment.NewLine)));
    }
    public void EmptyHeading()
    {
        var lines = new List <Line>
        {
            new Line("##", "", 0)
        };

        Assert.Empty(TocBuilder.BuildToc(lines, 1, new List <string>(), Environment.NewLine));
    }
    public Task Single()
    {
        var lines = new List <Line>
        {
            new Line("## Heading", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 1, new List <string>(), Environment.NewLine)));
    }
    public Task IgnoreTop()
    {
        var lines = new List <Line>
        {
            new("# Heading1", "", 0),
            new("## Heading2", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 1, new List <string>(), Environment.NewLine)));
    }
    public Task Exclude()
    {
        List <Line> lines = new()
        {
            new("## Heading1", "", 0),
            new("### Heading2", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 1, new() { "Heading2" }, Environment.NewLine)));
    }
    public Task StopAtLevel()
    {
        var lines = new List <Line>
        {
            new Line("## Heading1", "", 0),
            new Line("### Heading2", "", 0),
            new Line("#### Heading3", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 2, new List <string>(), Environment.NewLine)));
    }
    public Task DuplicateNested()
    {
        var lines = new List <Line>
        {
            new Line("## Heading", "", 0),
            new Line("### Heading", "", 0),
            new Line("#### Heading", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 4, new List <string>(), Environment.NewLine)));
    }
    public Task Duplicates()
    {
        var lines = new List <Line>
        {
            new("## A", "", 0),
            new("## A", "", 0),
            new("## a", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 1, new List <string>(), Environment.NewLine)));
    }
    public Task EmptyHeading()
    {
        var lines = new List <Line>
        {
            new Line("##", "", 0)
        };

        var buildToc = TocBuilder.BuildToc(lines, 1, new List <string>(), "\r");

        Assert.DoesNotContain("\r\n", buildToc);
        return(Verifier.Verify(buildToc));
    }
    public Task Deep()
    {
        var lines = new List <Line>
        {
            new Line("## Heading1", "", 0),
            new Line("### Heading2", "", 0),
            new Line("#### Heading3", "", 0),
            new Line("##### Heading4", "", 0)
        };

        return(Verify(TocBuilder.BuildToc(lines, 10, new List <string>(), Environment.NewLine)));
    }
    public Task Exclude()
    {
        var lines = new List <Line>
        {
            new Line("## Heading1", "", 0),
            new Line("### Heading2", "", 0)
        };

        return(Verify(TocBuilder.BuildToc(lines, 1, new List <string> {
            "Heading2"
        }, Environment.NewLine)));
    }
    public Task Nested()
    {
        List <Line> lines = new()
        {
            new("## Heading1", "", 0),
            new("### Heading2", "", 0),
            new("## Heading3", "", 0),
            new("### Heading4", "", 0)
        };

        return(Verifier.Verify(TocBuilder.BuildToc(lines, 2, new(), Environment.NewLine)));
    }
 public Task SanitizeLink()
 {
     return(Verifier.Verify(TocBuilder.SanitizeLink("A!@#$%,^&*()_+-={};':\"<>?/b")));
 }
        internal ProcessResult Apply(List <Line> lines, string newLine, string?relativePath)
        {
            var  missingSnippets  = new List <MissingSnippet>();
            var  validationErrors = new List <ValidationError>();
            var  missingIncludes  = new List <MissingInclude>();
            var  usedSnippets     = new List <Snippet>();
            var  usedIncludes     = new List <Include>();
            var  builder          = new StringBuilder();
            Line?tocLine          = null;
            var  headerLines      = new List <Line>();

            for (var index = 0; index < lines.Count; index++)
            {
                var line = lines[index];

                if (validateContent)
                {
                    var errors = ContentValidation.Verify(line.Original).ToList();
                    if (errors.Any())
                    {
                        validationErrors.AddRange(errors.Select(error => new ValidationError(error.error, line.LineNumber, error.column, line.Path)));
                        continue;
                    }
                }

                if (includeProcessor.TryProcessInclude(lines, line, usedIncludes, index, missingIncludes))
                {
                    continue;
                }

                if (line.Current.StartsWith("#"))
                {
                    if (tocLine != null)
                    {
                        headerLines.Add(line);
                    }

                    continue;
                }

                if (line.Current == "toc")
                {
                    tocLine = line;
                    continue;
                }

                if (SnippetKeyReader.TryExtractKeyFromLine(line, out var key))
                {
                    builder.Clear();

                    void AppendLine(string s)
                    {
                        builder.Append(s);
                        builder.Append(newLine);
                    }

                    ProcessSnippetLine(AppendLine, missingSnippets, usedSnippets, key, line);
                    builder.TrimEnd();
                    line.Current = builder.ToString();
                }
            }

            if (writeHeader)
            {
                lines.Insert(0, new Line(HeaderWriter.WriteHeader(relativePath !, header, newLine), "", 0));
            }

            if (tocLine != null)
            {
                tocLine.Current = TocBuilder.BuildToc(headerLines, tocLevel, tocExcludes, newLine);
            }

            return(new ProcessResult(
                       missingSnippets: missingSnippets,
                       usedSnippets: usedSnippets.Distinct().ToList(),
                       usedIncludes: usedIncludes.Distinct().ToList(),
                       missingIncludes: missingIncludes,
                       validationErrors: validationErrors));
        }
        internal ProcessResult Apply(List <Line> lines, string newLine, string?relativePath)
        {
            var  missingSnippets  = new List <MissingSnippet>();
            var  validationErrors = new List <ValidationError>();
            var  missingIncludes  = new List <MissingInclude>();
            var  usedSnippets     = new List <Snippet>();
            var  usedIncludes     = new List <Include>();
            var  builder          = new StringBuilder();
            Line?tocLine          = null;

            void AppendLine(string s)
            {
                builder.Append(s);
                builder.Append(newLine);
            }

            var headerLines = new List <Line>();

            for (var index = 0; index < lines.Count; index++)
            {
                var line = lines[index];

                if (ValidateContent(relativePath, line, validationErrors))
                {
                    continue;
                }

                if (includeProcessor.TryProcessInclude(lines, line, usedIncludes, index, missingIncludes, relativePath))
                {
                    continue;
                }

                if (line.Current.StartsWith("#"))
                {
                    if (tocLine != null)
                    {
                        headerLines.Add(line);
                    }

                    continue;
                }

                if (line.Current == "toc")
                {
                    tocLine = line;
                    continue;
                }

                void AppendSnippet(string key1)
                {
                    builder.Clear();
                    ProcessSnippetLine(AppendLine, missingSnippets, usedSnippets, key1, relativePath, line);
                    builder.TrimEnd();
                    line.Current = builder.ToString();
                }

                if (SnippetKey.ExtractSnippet(line, out var key))
                {
                    AppendSnippet(key);
                    continue;
                }

                if (convention == DocumentConvention.SourceTransform)
                {
                    continue;
                }

                if (SnippetKey.ExtractStartCommentSnippet(line, out key))
                {
                    AppendSnippet(key);

                    index++;

                    lines.RemoveUntil(
                        index,
                        "<!-- endSnippet -->",
                        relativePath,
                        line);
                    continue;
                }

                if (line.Current == "<!-- toc -->")
                {
                    tocLine = line;

                    index++;

                    lines.RemoveUntil(index, "<!-- endToc -->", relativePath, line);

                    continue;
                }
            }

            if (writeHeader)
            {
                lines.Insert(0, new Line(HeaderWriter.WriteHeader(relativePath !, header, newLine), "", 0));
            }

            if (tocLine != null)
            {
                tocLine.Current = TocBuilder.BuildToc(headerLines, tocLevel, tocExcludes, newLine);
            }

            return(new ProcessResult(
                       missingSnippets: missingSnippets,
                       usedSnippets: usedSnippets.Distinct().ToList(),
                       usedIncludes: usedIncludes.Distinct().ToList(),
                       missingIncludes: missingIncludes,
                       validationErrors: validationErrors));
        }