private static void Render(MarkdownDocument doc, string fileName)
        {
            Console.WriteLine("Creating {0}", fileName);

            string directoryName = Path.GetDirectoryName(fileName);

            if (!Directory.Exists(directoryName))
            {
                Directory.CreateDirectory(directoryName);
            }

            var options = new NormalizeOptions();

            using (var writer = new StreamWriter(fileName))
            {
                var renderer = new NormalizeRenderer(writer, options);
                renderer.ObjectRenderers.Add(new NormalizeTableRenderer());
                var linkReferenceDefinitionRenderer = renderer.ObjectRenderers.Find <LinkReferenceDefinitionRenderer>();
                if (linkReferenceDefinitionRenderer != null)
                {
                    renderer.ObjectRenderers.Remove(linkReferenceDefinitionRenderer);
                }

                renderer.Render(doc);
            }
        }
Example #2
0
        private static void AppendInline(Inline inline, StringWriter writer, NormalizeRenderer renderer)
        {
            switch (inline)
            {
            case LineBreakInline:
                writer.Write(' ');
                break;

            case EmphasisInline emphasis:
                foreach (var item in emphasis)
                {
                    AppendInline(item, writer, renderer);
                }
                break;

            case CodeInline code:
                writer.Write(code.Content);
                break;

            case LinkInline link:
                foreach (var item in link)
                {
                    AppendInline(item, writer, renderer);
                }
                writer.Write($" ({link.Url})");
                break;

            default:
                renderer.Render(inline);
                break;
            }
        }
Example #3
0
        private static string RenderToString(MarkdownDocument document)
        {
            using var writer = new StringWriter { NewLine = "\n" };
            var renderer = new NormalizeRenderer(writer);

            renderer.Render(document);
            return(writer.ToString());
        }
Example #4
0
            public MarkdownSource Update()
            {
                using var writer = new StringWriter();
                var renderer = new NormalizeRenderer(writer);

                renderer.Render(Document);

                return(new MarkdownSource(writer.ToString()));
            }
        protected override void Write(NormalizeRenderer renderer, Table obj)
        {
            renderer.EnsureLine();

            foreach (var row in obj.OfType <TableRow>())
            {
                renderer.Write(PipeSeparator);

                foreach (var tableCell in row)
                {
                    renderer.Write(MarginSeparator);

                    renderer.Render(tableCell);

                    renderer.Write(MarginSeparator);
                    renderer.Write(PipeSeparator);
                }

                renderer.WriteLine();


                if (row.IsHeader)
                {
                    bool alignmentEnabled = obj.ColumnDefinitions.Any(c => c.Alignment != TableColumnAlign.Left);

                    renderer.Write(PipeSeparator);

                    foreach (var column in obj.ColumnDefinitions)
                    {
                        renderer.Write(MarginSeparator);
                        if (alignmentEnabled && (column.Alignment == TableColumnAlign.Left || column.Alignment == TableColumnAlign.Center))
                        {
                            renderer.Write(AlignmentChar);
                        }
                        renderer.Write(HeaderSeparator);
                        if (alignmentEnabled && (column.Alignment == TableColumnAlign.Right || column.Alignment == TableColumnAlign.Center))
                        {
                            renderer.Write(AlignmentChar);
                        }
                        renderer.Write(MarginSeparator);
                        renderer.Write(PipeSeparator);
                    }

                    renderer.WriteLine();
                }
            }

            renderer.FinishBlock(true);
        }
            static string ToMarkdown(IEnumerable <Block> blocks)
            {
                var writer   = new StringWriter();
                var renderer = new NormalizeRenderer(writer);
                var pipeline = new MarkdownPipelineBuilder().Build();

                pipeline.Setup(renderer);
                foreach (var block in blocks)
                {
                    renderer.Render(block);
                }
                // We convert \n to \r because the YAML serialization will eventually
                // output \n\n for \n, but \r\n for \r.
                return(writer.ToString().TrimEnd().Replace('\n', '\r'));
            }
Example #7
0
        public void RenderMarkdown(string fileName, MarkdownDocument document)
        {
            if (!_renderSettings.RenderMarkdown)
            {
                return;
            }
            string renamedFileName = fileName.Substring(0, fileName.Length - 3) + ".normalized.md";
            var    file            = new File(_renderSettings.MarkdownFolder, renamedFileName);

            using (var writer = new StreamWriter(file.AbsolutePath))
            {
                var normalizeRenderer = new NormalizeRenderer(writer);
                normalizeRenderer.Render(document);
            }
        }
        // notes may contain html and markdown, so to include:
        // 1. Convert html into markdown
        // 2. Parse markdown into ast
        // 3. Normalize headings
        // 4. Convert ast into markdown text
        // 5. Add markdown text to stream
        public string Normalize(string text)
        {
            string           markdownText = _converter.Convert(text);
            MarkdownDocument markdown     = Markdown.Parse(markdownText);

            using (var writer = new StringWriter())
            {
                var pipeline = new MarkdownPipelineBuilder().Build();
                pipeline.Extensions.AddIfNotAlready <SoftlineBreakAsHardlineExtension>();
                var renderer = new NormalizeRenderer(writer);
                pipeline.Setup(renderer);
                renderer.Render(markdown);
                writer.Flush();
                return(writer.ToString());
            }
        }
Example #9
0
        /// <summary>
        /// Normalizes the specified markdown to a normalized markdown text.
        /// </summary>
        /// <param name="markdown">The markdown.</param>
        /// <param name="writer">The destination <see cref="TextWriter"/> that will receive the result of the conversion.</param>
        /// <param name="options">The normalize options</param>
        /// <param name="pipeline">The pipeline.</param>
        /// <param name="context">A parser context used for the parsing.</param>
        /// <returns>A normalized markdown text.</returns>
        public static MarkdownDocument Normalize(string markdown, TextWriter writer, NormalizeOptions options = null, MarkdownPipeline pipeline = null, MarkdownParserContext context = null)
        {
            pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
            pipeline = CheckForSelfPipeline(pipeline, markdown);

            // We override the renderer with our own writer
            var renderer = new NormalizeRenderer(writer, options);

            pipeline.Setup(renderer);

            var document = Parse(markdown, pipeline, context);

            renderer.Render(document);
            writer.Flush();

            return(document);
        }
Example #10
0
        /*
         * public static Item ToItem(string md)
         * {
         *  var pipeline = new MarkdownPipelineBuilder().UsePipeTables().Build();
         *  var document = MarkdownParser.Parse(md, pipeline);
         *
         *  var enumerator = document.GetEnumerator();
         *  try
         *  {
         *      enumerator.MoveNext();
         *      while (enumerator.Current != null)
         *      {
         *          var block = enumerator.Current;
         *
         *          if (block is HtmlBlock)
         *          {
         *              if (block.IsNewItem())
         *              {
         *                  var item = ParseItem(ref enumerator);
         *                  return item;
         *              }
         *          }
         *          enumerator.MoveNext();
         *      }
         *
         *  }
         *  finally
         *  {
         *      enumerator.Dispose();
         *  }
         *  return null;
         * }
         *
         * public static Item ParseItem(ref ContainerBlock.Enumerator enumerator)
         * {
         *  var currentItem = enumerator.Current.GetNewItem();
         *
         *  if (currentItem != null)
         *  {
         *      enumerator.MoveNext();
         *      while (enumerator.Current != null)
         *      {
         *          var block = enumerator.Current;
         *
         *          if (block is HtmlBlock)
         *          {
         *              if (block.IsClosingItem())
         *              {
         *                  return currentItem;
         *              }
         *              else if (block.IsNewItem())
         *              {
         *                  var subItem = ParseItem(ref enumerator);
         *
         *                  var propertyName = subItem.GetType().Name;
         *
         *                  if (currentItem.GetType().GetProperty(propertyName) != null)
         *                  {
         *                      PropertyInfo prop = currentItem.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
         *                      if (null != prop && prop.CanWrite)
         *                      {
         *                          prop.SetValue(currentItem, subItem, null);
         *                      }
         *                  }
         *                  else if (currentItem is Items)
         *                  {
         *                      var items = currentItem as Items;
         *                      items.Add(subItem);
         *                  }
         *              }
         *          }
         *
         *          else // if (block is ContainerBlock)
         *          {
         *              ParseItemProperties(currentItem, block);
         *          }
         *
         *          currentItem.Markdown += enumerator.Current.ToMarkdownString();
         *
         *          enumerator.MoveNext();
         *      }
         *  }
         *
         *  return currentItem;
         * }
         *
         * public static void ParseItemProperties(Item item, Block block)
         * {
         *  switch(block)
         *  {
         *      case Markdig.Extensions.Tables.Table table:
         *          ParseItemProperties(item, table);
         *          break;
         *      case ContainerBlock blocks:
         *          ParseItemProperties(item, blocks);
         *          break;
         *      case LeafBlock leaf:
         *          ParseItemProperties(item, leaf.Inline);
         *          break;
         *  }
         * }
         *
         * public static void ParseItemProperties(Item item, ContainerBlock blocks)
         * {
         *  foreach(var block in blocks)
         *  {
         *      ParseItemProperties(item, block);
         *  }
         * }
         *
         * public static void ParseItemProperties(Item item, ContainerInline inlines)
         * {
         *  if(inlines == null)
         *  {
         *      return;
         *  }
         *  PropertyInfo prop = null;
         *  foreach (var inline in inlines)
         *  {
         *      if(inline is HtmlInline)
         *      {
         *          var tag = (inline as HtmlInline).Tag;
         *          if(tag == "<!--br-->" || tag =="<br>")
         *          {
         *
         *          }
         *          else if (tag.StartsWith("<!--/"))
         *          {
         *              prop = null;
         *          }
         *          else if (tag.StartsWith("<!--") && !tag.StartsWith("<!--/"))
         *          {
         *              var propertyName = tag.Substring(4, tag.Length - 7);
         *              prop = item.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
         *          }
         *      }
         *      else
         *      {
         *          if (null != prop && prop.CanWrite)
         *          {
         *              prop.SetValue(item, inline.ToMarkdownString(), null);
         *          }
         *      }
         *  }
         * }
         *
         *
         *
         * public static bool IsNewItem(this Block block)
         * {
         *  var htmlBlock = block as HtmlBlock;
         *  if (htmlBlock.Type == HtmlBlockType.Comment)
         *  {
         *      var tag = htmlBlock.Lines.Lines.FirstOrDefault().Slice.ToString();
         *      if (!string.IsNullOrEmpty(tag) && tag != "<!--br-->" && tag != "<br>")
         *      {
         *          if (tag.StartsWith("<!--") && !tag.StartsWith("<!--/"))
         *          {
         *              return true;
         *          }
         *      }
         *  }
         *  return false;
         * }
         *
         * public static bool IsClosingItem(this Block block)
         * {
         *  var htmlBlock = block as HtmlBlock;
         *  if (htmlBlock.Type == HtmlBlockType.Comment)
         *  {
         *      var tag = htmlBlock.Lines.Lines.FirstOrDefault().Slice.ToString();
         *      if (!string.IsNullOrEmpty(tag) && tag != "<!--br-->" && tag != "<br>")
         *      {
         *          if (tag.StartsWith("<!--/"))
         *          {
         *              return true;
         *          }
         *      }
         *  }
         *  return false;
         * }
         *
         * public static Item GetNewItem(this Block block)
         * {
         *  var htmlBlock = block as HtmlBlock;
         *  if (htmlBlock.Type == HtmlBlockType.Comment)
         *  {
         *      var tag = htmlBlock.Lines.Lines.FirstOrDefault().Slice.ToString();
         *      if (!string.IsNullOrEmpty(tag) && tag != "<!--br-->" && tag != "<br>")
         *      {
         *          if (tag.StartsWith("<!--") && !tag.StartsWith("<!--/"))
         *          {
         *              var name = $"AideDeJeuLib.{tag.Substring(4, tag.Length - 7)}, AideDeJeu";
         *              var type = Type.GetType(name);
         *              var instance = Activator.CreateInstance(type) as Item;
         *              return instance;
         *          }
         *      }
         *  }
         *  return null;
         * }
         */

        /*
         * public static Item ToItem(string md)
         * {
         *  var pipeline = new MarkdownPipelineBuilder().UsePipeTables().Build();
         *  var document = MarkdownParser.Parse(md, pipeline);
         *
         *  var enumerator = document.GetEnumerator();
         *  try
         *  {
         *      enumerator.MoveNext();
         *      while (enumerator.Current != null)
         *      {
         *          var block = enumerator.Current;
         *
         *          if (enumerator.Current is ParagraphBlock)
         *          {
         *              if(block.IsNewItem())
         *              {
         *                  var item = block.GetNewItem();
         *                  item.Parse(ref enumerator);
         *                  return item;
         *              }
         *          }
         *          enumerator.MoveNext();
         *      }
         *
         *  }
         *  finally
         *  {
         *      enumerator.Dispose();
         *  }
         *  return null;
         * }
         *
         * public static bool IsNewItem(this Block block)
         * {
         *  var paragraphBlock = block as ParagraphBlock;
         *  var linkInline = paragraphBlock?.Inline?.FirstChild as LinkInline;
         *  if (linkInline != null)
         *  {
         *      var label = linkInline.Label;
         *      var title = linkInline.Title;
         *      if (title == string.Empty && label != string.Empty)
         *      {
         *          return true;
         *      }
         *  }
         *  return false;
         * }
         *
         * public static bool IsClosingItem(this Block block)
         * {
         *  var paragraphBlock = block as ParagraphBlock;
         *  var linkInline = paragraphBlock?.Inline?.FirstChild as LinkInline;
         *  if (linkInline != null)
         *  {
         *      var label = linkInline.Label;
         *      var title = linkInline.Title;
         *      if (title == string.Empty && label == string.Empty)
         *      {
         *          return true;
         *      }
         *  }
         *  return false;
         * }
         *
         * public static Item GetNewItem(this Block block)
         * {
         *  var paragraphBlock = block as ParagraphBlock;
         *  var linkInline = paragraphBlock?.Inline?.FirstChild as LinkInline;
         *  if (linkInline != null)
         *  {
         *      var label = linkInline.Label;
         *      var title = linkInline.Title;
         *      var url = linkInline.Url;
         *      if (title == string.Empty)
         *      {
         *          var name = $"AideDeJeuLib.{label}, AideDeJeu";
         *          var type = Type.GetType(name);
         *          var instance = Activator.CreateInstance(type) as Item;
         *          return instance;
         *      }
         *  }
         *  return null;
         * }
         */


        public static string ToMarkdownString(this Block block)
        {
            var pipeline = new MarkdownPipelineBuilder()
                           .UsePipeTables()
                           .Build();

            using (var writer = new StringWriter())
            {
                var renderer = new NormalizeRenderer(writer);
                renderer.ObjectRenderers.Remove(renderer.ObjectRenderers.FirstOrDefault(i => i is LinkInlineRenderer));
                renderer.ObjectRenderers.Add(new LinkInlineRendererEx());
                renderer.ObjectRenderers.Add(new TableRenderer());
                pipeline.Setup(renderer);

                renderer.Render(block);
                return(writer.ToString());
            }
        }
Example #11
0
        public string Process(string text, Func <long, string> urlGenerator)
        {
            MarkdownDocument markdown = Markdown.Parse(text);

            foreach (var link in markdown.Descendants().Where(e => e is LinkInline).Cast <LinkInline>())
            {
                if (int.TryParse(link.Url, out var dataIndex))
                {
                    link.Url = urlGenerator(dataIndex);
                }
            }

            var writer = new StringWriter();
            NormalizeRenderer renderer = new NormalizeRenderer(writer);

            renderer.Render(markdown);

            return(writer.ToString());
        }
Example #12
0
        /// <summary>
        /// Normalizes the specified markdown to a normalized markdown text.
        /// </summary>
        /// <param name="markdown">The markdown.</param>
        /// <param name="writer">The destination <see cref="TextWriter"/> that will receive the result of the conversion.</param>
        /// <param name="options">The normalize options</param>
        /// <param name="pipeline">The pipeline.</param>
        /// <param name="context">A parser context used for the parsing.</param>
        /// <returns>A normalized markdown text.</returns>
        public static MarkdownDocument Normalize(string markdown, TextWriter writer, NormalizeOptions?options = null, MarkdownPipeline?pipeline = null, MarkdownParserContext?context = null)
        {
            if (markdown is null)
            {
                ThrowHelper.ArgumentNullException_markdown();
            }

            pipeline = GetPipeline(pipeline, markdown);

            var document = MarkdownParser.Parse(markdown, pipeline, context);

            var renderer = new NormalizeRenderer(writer, options);

            pipeline.Setup(renderer);

            renderer.Render(document);
            writer.Flush();

            return(document);
        }
Example #13
0
        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);
        }
Example #14
0
        public async Task <string> SolveImagesUrlAsync(string source, Func <string, Task <string> > converter)
        {
            using (var tw = new StringWriter())
            {
                var writer = new NormalizeRenderer(tw);
                Pipeline.Setup(writer);
                var doc1 = Parse(source);

                await doc1.TransverseAsync <LinkInline>(async item =>
                {
                    if (item.IsImage)
                    {
                        item.Url = await converter(item.Url);
                    }
                });

                writer.Render(doc1);
                writer.Writer.Flush();
                return(tw.ToString());
            }
        }
Example #15
0
        public override void Transform(ExtensionHtmlRenderer extensionHtmlRenderer, WorkflowNotesBlock block, Diagram diagram)
        {
            var(element, elementsEnumerable) = _provider.GetBpmnElements(new EaProvider.Path(diagram.Name));
            var elements = elementsEnumerable.ToList();

            elements.Sort(new BpmnElement.AliasComparer());
            var sb = new StringBuilder();

            sb.AppendLine($@"# {element.Name}");
            var converter = new Html2Markdown.Converter();

            foreach (BpmnElement e in elements)
            {
                string           name    = string.IsNullOrEmpty(e.Name) ? e.Alias : e.Name;
                string           notes   = converter.Convert(e.Notes);
                MarkdownDocument notesMd = Markdown.Parse(notes);
                notesMd.IncreaseHeadingLevel(2);
                string normalizedNotes = null;
                using (var writer = new StringWriter())
                {
                    var pipeline = new MarkdownPipelineBuilder().Build();
                    pipeline.Extensions.AddIfNotAlready <SoftlineBreakAsHardlineExtension>();
                    var renderer = new NormalizeRenderer(writer);
                    pipeline.Setup(renderer);
                    renderer.Render(notesMd);
                    writer.Flush();
                    normalizedNotes = writer.ToString();
                }

                sb.AppendLine($@"## {name}");
                sb.AppendLine($@"Lane: {e.Lane}");
                sb.AppendLine();
                sb.AppendLine($@"Description:");
                sb.AppendLine(normalizedNotes);
            }
            MarkdownDocument document = Markdown.Parse(sb.ToString());

            Replace(block, document);
        }
Example #16
0
        public static string Converter(string mixedHtmlAndMarkdown, Action <MarkdownDocument> transform, MarkdownPipeline pipeline)
        {
            var    converter    = new Html2Markdown.Converter();
            string markdownOnly = converter.Convert(mixedHtmlAndMarkdown);

            pipeline = new MarkdownPipelineBuilder()
                       .UseAdvancedExtensions()
                       .UsePipeTables()
                       .UseGridTables()
                       .Build();
            pipeline.Extensions.AddIfNotAlready <SoftlineBreakAsHardlineExtension>();
            MarkdownDocument ast = Markdown.Parse(markdownOnly, pipeline);

            transform(ast);
            using (var writer = new StringWriter())
            {
                var renderer = new NormalizeRenderer(writer);
                pipeline.Setup(renderer);
                renderer.Render(ast);
                writer.Flush();
                return(writer.ToString());
            }
        }
Example #17
0
        private static void AppendBlock(Block block, StringWriter writer, NormalizeRenderer renderer)
        {
            switch (block)
            {
            case HeadingBlock heading:
                writer.Write('[');
                foreach (var item in heading.Inline)
                {
                    AppendInline(item, writer, renderer);
                }
                writer.WriteLine(']');
                break;

            case QuoteBlock quote:
                foreach (var item in quote)
                {
                    using var nestedWriter = new StringWriter { NewLine = "\n" };
                    var nestedRenderer = new NormalizeRenderer(nestedWriter);
                    AppendBlock(item, nestedWriter, nestedRenderer);

                    var quotedLines = nestedWriter.ToString().Split("\n");
                    for (var i = 0; i < quotedLines.Length; ++i)
                    {
                        var line = quotedLines[i];
                        if (i == quotedLines.Length - 1 && line == "")
                        {
                            continue;
                        }
                        writer.WriteLine($"> {line}");
                    }
                }
                break;

            case CodeBlock code:
                for (var index = 0; index < code.Lines.Count; ++index)
                {
                    writer.WriteLine(code.Lines.Lines[index]);
                }
                break;

            case ParagraphBlock paragraph:
                foreach (var item in paragraph.Inline)
                {
                    AppendInline(item, writer, renderer);
                }
                writer.WriteLine();
                break;

            case ThematicBreakBlock:
                writer.WriteLine("* * *");
                break;

            case ListBlock {
                    BulletType: '1'
            } list:
                var number = 1;
                foreach (var item in list)
                {
                    writer.Write($"{number++}. ");
                    AppendBlock(item, writer, renderer);
                }
                break;

            case ListBlock list:
                foreach (var item in list)
                {
                    writer.Write("- ");
                    AppendBlock(item, writer, renderer);
                }
                break;

            case LinkReferenceDefinitionGroup _:
                // Handled automatically when processing links; no output is expected.
                break;

            case ContainerBlock container:
                foreach (var item in container)
                {
                    AppendBlock(item, writer, renderer);
                }
                break;

            default:
                renderer.Render(block);
                break;
            }
        }
Example #18
0
        /// <summary>
        /// Constructs a DocComment instance from the documentation comments
        /// associated with a source code element.
        /// </summary>
        /// <param name="docComments">The doc comments from the source code</param>
        /// <param name="name">The name of the element</param>
        /// <param name="deprecated">Flag indicating whether or not the element had a Deprecated attribute</param>
        /// <param name="replacement">The name of the replacement element for deprecated elements, if given</param>
        public DocComment(IEnumerable <string> docComments, string name, bool deprecated, string replacement)
        {
            string GetHeadingText(HeadingBlock heading)
            {
                var sb = new StringBuilder();

                foreach (var item in heading.Inline)
                {
                    sb.Append(item.ToString());
                }
                return(sb.ToString());
            }

            string GetParagraphText(LeafBlock leaf)
            {
                var sb = new StringBuilder();

                foreach (var item in leaf.Inline)
                {
                    sb.Append(item.ToString());
                }
                return(sb.ToString());
            }

            string ToMarkdown(IEnumerable <Block> blocks)
            {
                var writer   = new StringWriter();
                var renderer = new NormalizeRenderer(writer);
                var pipeline = new MarkdownPipelineBuilder().Build();

                pipeline.Setup(renderer);
                foreach (var block in blocks)
                {
                    renderer.Render(block);
                }
                // We convert \n to \r because the YAML serialization will eventually
                // output \n\n for \n, but \r\n for \r.
                return(writer.ToString().TrimEnd().Replace('\n', '\r'));
            }

            List <ValueTuple <string, List <Block> > > BreakIntoSections(IEnumerable <Block> blocks, int level)
            {
                var key    = "";
                var accum  = new List <Block>();
                var result = new List <ValueTuple <string, List <Block> > >();

                foreach (var block in blocks)
                {
                    if (block is HeadingBlock heading)
                    {
                        if (heading.Level == level)
                        {
                            if (accum.Count > 0)
                            {
                                result.Add(new ValueTuple <string, List <Block> >(key, accum));
                                accum = new List <Block>();
                            }
                            key = GetHeadingText(heading);
                        }
                        else
                        {
                            accum.Add(block);
                        }
                    }
                    else
                    {
                        accum.Add(block);
                    }
                }

                if (accum.Count > 0)
                {
                    result.Add(new ValueTuple <string, List <Block> >(key, accum));
                }

                return(result);
            }

            void ParseListSection(IEnumerable <Block> blocks, List <string> accum, bool lowerCase)
            {
                foreach (var block in blocks)
                {
                    if (block is ListBlock list)
                    {
                        foreach (var sub in block.Descendants())
                        {
                            if (sub is ListItemBlock item)
                            {
                                // Some special treatment for funky doc comments in some of the Canon
                                if (item.Count == 1 && item.LastChild is LeafBlock leaf && leaf.Inline != null &&
                                    leaf.Inline.FirstChild is LiteralInline literal)
                                {
                                    var itemText = lowerCase ? GetParagraphText(leaf).ToLowerInvariant() : GetParagraphText(leaf);
                                    if (itemText.StartsWith("@\"") && itemText.EndsWith("\""))
                                    {
                                        itemText = itemText.Substring(2, itemText.Length - 3);
                                    }
                                    literal.Content = new Markdig.Helpers.StringSlice(itemText.ToLowerInvariant());
                                }
                                accum.Add(ToMarkdown(new Block[] { item }));
                            }
                        }
                    }
                }
            }

            void ParseMapSection(IEnumerable <Block> blocks, Dictionary <string, string> accum)
            {
                var subsections = BreakIntoSections(blocks, 2);

                foreach ((var key, var subs) in subsections)
                {
                    // TODO: when we add the ability to flag warnings from the doc comment builder,
                    // we should check here for duplicate keys and generate a warning if appropriate.
                    accum[key] = ToMarkdown(subs);
                }
            }

            // First element is not matching, second is matching
            (List <Block>, List <Block>) PartitionNestedSection(IEnumerable <Block> blocks, int level, string name)
            {
                var inMatch = false;
                var result  = (new List <Block>(), new List <Block>());

                foreach (var block in blocks)
                {
                    var skip = false;
                    if ((block is HeadingBlock heading) && (heading.Level == level))
                    {
                        inMatch = GetHeadingText(heading).Equals(name);
                        skip    = true;
                    }
                    if (inMatch)
                    {
                        if (!skip)
                        {
                            result.Item2.Add(block);
                        }
                    }
                    else
                    {
                        result.Item1.Add(block);
                    }
                }

                return(result);
            }

            // Initialize to safe empty values
            this.Summary        = "";
            this.Description    = "";
            this.ShortSummary   = "";
            this.Documentation  = "";
            this.Input          = new Dictionary <string, string>();
            this.Output         = "";
            this.TypeParameters = new Dictionary <string, string>();
            this.Example        = "";
            this.Remarks        = "";
            this.SeeAlso        = new List <string>();
            this.References     = "";

            var deprecationSummary = String.IsNullOrWhiteSpace(replacement)
                                    ? DiagnosticItem.Message(WarningCode.DeprecationWithoutRedirect, new string[] { name })
                                    : DiagnosticItem.Message(WarningCode.DeprecationWithRedirect, new string[] { name, "@\"" + replacement + "\"" });
            var deprecationDetails = "";

            var text = String.Join("\n", docComments);

            // Only parse if there are comments to parse
            if (!string.IsNullOrWhiteSpace(text))
            {
                var          doc                = Markdown.Parse(text);
                var          sections           = BreakIntoSections(doc, 1);
                List <Block> summarySection     = new List <Block>();
                List <Block> descriptionSection = new List <Block>();

                foreach ((var tag, var section) in sections)
                {
                    switch (tag)
                    {
                    case "Summary":
                        this.Summary = ToMarkdown(section);
                        summarySection.AddRange(section);
                        // For now, the short hover information gets the first paragraph of the summary.
                        this.ShortSummary = ToMarkdown(section.GetRange(0, 1));
                        break;

                    case "Deprecated":
                        if (String.IsNullOrWhiteSpace(name))
                        {
                            deprecationSummary = ToMarkdown(section.GetRange(0, 1));
                            if (section.Count > 1)
                            {
                                deprecationDetails = ToMarkdown(section.GetRange(1, section.Count - 1));
                            }
                        }
                        else
                        {
                            deprecationDetails = ToMarkdown(section);
                        }
                        deprecated = true;
                        break;

                    case "Description":
                        this.Description   = ToMarkdown(section);
                        descriptionSection = section;
                        break;

                    case "Input":
                        ParseMapSection(section, this.Input);
                        break;

                    case "Output":
                        this.Output = ToMarkdown(section);
                        break;

                    case "Type Parameters":
                        ParseMapSection(section, this.TypeParameters);
                        break;

                    case "Example":
                        this.Example = ToMarkdown(section);
                        break;

                    case "Remarks":
                        (var remarks, var examples) = PartitionNestedSection(section, 2, "Example");
                        if ((examples.Count > 0) && (this.Example == ""))
                        {
                            this.Example = ToMarkdown(examples);
                        }
                        this.Remarks = ToMarkdown(remarks);
                        break;

                    case "See Also":
                        // seeAlso is a list of UIDs, which are all lower case,
                        // so pass true to lowercase all strings found in this section
                        ParseListSection(section, this.SeeAlso, true);
                        break;

                    case "References":
                        this.References = ToMarkdown(section);
                        break;

                    default:
                        // TODO: add diagnostic warning about unknown tag
                        break;
                    }
                }


                this.Documentation = ToMarkdown(summarySection.Concat(descriptionSection));
            }

            if (deprecated)
            {
                var shortDeprecationText = DeprecatedWarning + "\r" + deprecationSummary;
                var longDeprecationText  = shortDeprecationText + (String.IsNullOrWhiteSpace(deprecationDetails) ? "" : "\r") + deprecationDetails;
                this.Summary      += "\r" + longDeprecationText;
                this.ShortSummary  = shortDeprecationText;
                this.Documentation = deprecationSummary;
            }
        }
Example #19
0
        internal static void WriteTo(this MarkdownObject md, TextWriter writer, NormalizeOptions?options = null)
        {
            var renderer = new NormalizeRenderer(writer, options);

            renderer.Render(md);
        }