diff --git a/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java b/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java index 064d35930ce..c8ec46de4b4 100644 --- a/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java +++ b/core/src/org/labkey/core/wiki/MarkdownServiceImpl.java @@ -23,10 +23,15 @@ import org.commonmark.ext.image.attributes.ImageAttributesExtension; import org.commonmark.node.Node; import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlNodeRendererContext; import org.commonmark.renderer.html.HtmlRenderer; +import org.commonmark.renderer.html.CoreHtmlNodeRenderer; +import org.commonmark.node.HtmlInline; +import org.commonmark.node.HtmlBlock; import org.labkey.api.markdown.MarkdownService; import java.util.List; +import java.util.Set; public class MarkdownServiceImpl implements MarkdownService { @@ -55,10 +60,65 @@ public MarkdownServiceImpl() .softbreak("
\n") // See Issue #34169 .sanitizeUrls(true) .escapeHtml(true) + .nodeRendererFactory(CommentNodeRenderer::new) .extensions(extensions) .build(); } + private static class CommentNodeRenderer extends CoreHtmlNodeRenderer + { + private final HtmlNodeRendererContext _context; + + public CommentNodeRenderer(HtmlNodeRendererContext context) + { + super(context); + _context = context; + } + + @Override + public Set> getNodeTypes() + { + return Set.of(HtmlInline.class, HtmlBlock.class); + } + + @Override + public void render(Node node) + { + if (node instanceof HtmlInline inline) + { + String literal = inline.getLiteral(); + if (isComment(literal)) + { + _context.getWriter().raw(literal); + } + else + { + _context.getWriter().text(literal); + } + } + else if (node instanceof HtmlBlock block) + { + String literal = block.getLiteral(); + if (isComment(literal)) + { + _context.getWriter().raw(literal); + } + else + { + _context.getWriter().tag("p"); + _context.getWriter().text(literal); + _context.getWriter().tag("/p"); + _context.getWriter().line(); + } + } + } + + private boolean isComment(String literal) + { + return literal != null && literal.trim().startsWith(""); + } + } + @Override public String toHtml(String mdText) { diff --git a/core/src/org/labkey/core/wiki/MarkdownTestCase.java b/core/src/org/labkey/core/wiki/MarkdownTestCase.java index f1c6402f787..a54fcea07c4 100644 --- a/core/src/org/labkey/core/wiki/MarkdownTestCase.java +++ b/core/src/org/labkey/core/wiki/MarkdownTestCase.java @@ -15,7 +15,7 @@ class MarkdownTestCase extends Assert @Test public void testMdHeadingToHtml() { - MarkdownService markdownService = MarkdownService.get(); + MarkdownService markdownService = new MarkdownServiceImpl(); String testMdText = "# This is a H1 header"; String expectedHtmlText = "

This is a H1 header

\n
"; String htmlText = markdownService.toHtml(testMdText); @@ -28,7 +28,7 @@ public void testMdHeadingToHtml() @Test public void testMdBoldToHtml() { - MarkdownService markdownService = MarkdownService.get(); + MarkdownService markdownService = new MarkdownServiceImpl(); String testMdText = "**This is bold text**"; String expectedHtmlText = "

This is bold text

\n
"; String htmlText = markdownService.toHtml(testMdText); @@ -41,11 +41,10 @@ public void testMdBoldToHtml() @Test public void testMdHtmlTags() { - MarkdownService markdownService = MarkdownService.get(); - + MarkdownService markdownService = new MarkdownServiceImpl(); String testMdText = "

header

"; - String expectedHtmlText = "

<h2>header</h2>

\n
"; String htmlText = markdownService.toHtml(testMdText); + String expectedHtmlText = "

<h2>header</h2>

\n
"; assertEquals("The MarkdownService failed to correctly escape html tags.", expectedHtmlText, htmlText); testMdText = ""; @@ -60,7 +59,7 @@ public void testMdHtmlTags() @Test public void testMdComplexToHtml() { - MarkdownService markdownService = MarkdownService.get(); + MarkdownService markdownService = new MarkdownServiceImpl(); // this sample of markdown and translation taken from part of: https://markdown-it.github.io/ String testMdText = """ --- @@ -341,4 +340,20 @@ public void testMdComplexToHtml() String htmlText = markdownService.toHtml(testMdText); assertEquals("The MarkdownService failed to correctly translate complex markdown text to html.", expectedHtmlText, htmlText); } + @Test + public void testHtmlComments() + { + MarkdownService markdownService = new MarkdownServiceImpl(); + + String testMdText = "Text before text after"; + String htmlText = markdownService.toHtml(testMdText); + + assertTrue("Comment was encoded: " + htmlText, htmlText.contains("")); + assertFalse("Comment should not be encoded: " + htmlText, htmlText.contains("<!--")); + + // Verification for "; + String scriptHtml = markdownService.toHtml(scriptMd); + assertTrue("Script tags should still be encoded: " + scriptHtml, scriptHtml.contains("<script>")); + } }