/// <summary> /// Parses the specified markdown into an AST <see cref="MarkdownDocument"/> /// </summary> /// <param name="text">A Markdown text</param> /// <param name="pipeline">The pipeline used for the parsing.</param> /// <param name="context">A parser context used for the parsing.</param> /// <returns>An AST Markdown document</returns> /// <exception cref="ArgumentNullException">if reader variable is null</exception> public static MarkdownDocument Parse(string text, MarkdownPipeline?pipeline = null, MarkdownParserContext?context = null) { if (text is null) { ThrowHelper.ArgumentNullException_text(); } pipeline ??= Markdown.DefaultPipeline; text = FixupZero(text); var document = new MarkdownDocument { IsOpen = true }; if (pipeline.PreciseSourceLocation) { int roughLineCountEstimate = text.Length / 32; roughLineCountEstimate = Math.Max(4, Math.Min(512, roughLineCountEstimate)); document.LineStartIndexes = new List <int>(roughLineCountEstimate); } var blockProcessor = BlockProcessor.Rent(document, pipeline.BlockParsers, context, pipeline.TrackTrivia); try { blockProcessor.Open(document); ProcessBlocks(blockProcessor, new LineReader(text)); if (pipeline.TrackTrivia) { Block?lastBlock = blockProcessor.LastBlock; if (lastBlock is null && document.Count == 0) { // this means we have unassigned characters var noBlocksFoundBlock = new EmptyBlock(null); List <StringSlice> linesBefore = blockProcessor.UseLinesBefore(); noBlocksFoundBlock.LinesAfter = new List <StringSlice>(); noBlocksFoundBlock.LinesAfter.AddRange(linesBefore); document.Add(noBlocksFoundBlock); } else if (lastBlock != null && blockProcessor.LinesBefore != null) { // this means we're out of lines, but still have unassigned empty lines. // thus, we'll assign the empty unsassigned lines to the last block // of the document. var rootMostContainerBlock = Block.FindRootMostContainerParent(lastBlock); rootMostContainerBlock.LinesAfter ??= new List <StringSlice>(); var linesBefore = blockProcessor.UseLinesBefore(); rootMostContainerBlock.LinesAfter.AddRange(linesBefore); } } // At this point the LineIndex is the same as the number of lines in the document document.LineCount = blockProcessor.LineIndex; }