/// <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; }
private static MarkdownDocument CreateDocument(List <Block> blocks) { var result = new MarkdownDocument(); foreach (var block in blocks) { block.Parent?.Remove(block); result.Add(block); } return(result); }
private MarkdownDocument CreateDocument(List <Block> blocks) { var result = new MarkdownDocument(); foreach (var block in blocks) { block.Parent?.Remove(block); result.Add(block); } result.SetData("filePath", _file); return(result); }
protected async Task <MarkdownDocument> ExtractVersionDocument(MarkdownStream changelogMarkdown) { using var reader = new StreamReader(changelogMarkdown.Stream, leaveOpen: true); var text = await reader.ReadToEndAsync(); var document = Markdown.Parse(text); var nodes = ExtractDocumentBlocksDestructively(document).ToList(); var sectionDocument = new MarkdownDocument(); foreach (var block in nodes) { sectionDocument.Add(block); } return(sectionDocument); }
private MarkdownDocument CreateDocument(MarkdownPropertyModel model) { var result = new MarkdownDocument(); if (model != null) { foreach (var block in model.PropertyValue) { block.Parent?.Remove(block); result.Add(block); } result.SetData("filePath", _file); result.SetData(Constants.OPathStringDataName, model.PropertyName); result.SetData(Constants.OPathLineNumberDataName, model.PropertyNameSource.Line + 1); } return(result); }
private static MarkdownDocument ExtractChangelogFromBody(string markdownText) { if (string.IsNullOrEmpty(markdownText)) { throw new ArgumentNullException(nameof(markdownText)); } MarkdownDocument markdownDocument = Markdown.Parse(markdownText); MarkdownDocument result = new MarkdownDocument(); foreach (Block block in markdownDocument.SkipWhile(block => !(block is HeadingBlock headingBlock) || (headingBlock.Inline.FirstChild == null) || !(headingBlock.Inline.FirstChild is LiteralInline literalInline) || (literalInline.Content.ToString() != "Changelog")).Skip(1).TakeWhile(block => !(block is ThematicBreakBlock)).ToList()) { // All blocks that we're interested in must be removed from original markdownDocument firstly markdownDocument.Remove(block); result.Add(block); } return(result); }
private static void AssertSyntax(string expected, MarkdownObject syntax) { var writer = new StringWriter(); var normalizer = new NormalizeRenderer(writer); var document = new MarkdownDocument(); if (syntax is Block) { document.Add(syntax as Block); } else { throw new InvalidOperationException(); } normalizer.Render(document); var actual = writer.ToString(); Assert.AreEqual(expected, actual); }
private void ProcessBlocks() { while (true) { // Get the precise position of the begining of the line var lineText = lineReader.ReadLine(); // If this is the end of file and the last line is empty if (lineText.Text is null) { if (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); } } break; } blockProcessor.ProcessLine(lineText); }