diff --git a/libraries-formatting/pom.xml b/libraries-formatting/pom.xml
new file mode 100644
index 000000000000..37422e934f5a
--- /dev/null
+++ b/libraries-formatting/pom.xml
@@ -0,0 +1,39 @@
+
+
+ 4.0.0
+ libraries-formatting
+
+
+ parent-modules
+ com.baeldung
+ 1.0.0-SNAPSHOT
+
+
+
+
+ org.commonmark
+ commonmark
+ ${commonmark.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 21
+ 21
+
+
+
+
+
+
+ 0.28.0
+
+
+
diff --git a/libraries-formatting/src/main/java/com/baeldung/commonmark/CommonMarkUsage.java b/libraries-formatting/src/main/java/com/baeldung/commonmark/CommonMarkUsage.java
new file mode 100644
index 000000000000..b361eba26311
--- /dev/null
+++ b/libraries-formatting/src/main/java/com/baeldung/commonmark/CommonMarkUsage.java
@@ -0,0 +1,68 @@
+package com.baeldung.commonmark;
+
+import org.commonmark.node.Document;
+import org.commonmark.node.Heading;
+import org.commonmark.node.Node;
+import org.commonmark.node.Text;
+import org.commonmark.parser.Parser;
+import org.commonmark.renderer.html.HtmlRenderer;
+import org.commonmark.renderer.markdown.MarkdownRenderer;
+
+public class CommonMarkUsage {
+
+ public static String markDownToHtml(String markdown) {
+ Parser parser = Parser.builder()
+ .build();
+ Node node = parser.parse(markdown);
+ HtmlRenderer renderer = HtmlRenderer.builder()
+ .build();
+ return renderer.render(node);
+
+ }
+
+ public static int processParsedNode(String markdown) {
+ Parser parser = Parser.builder()
+ .build();
+ Node node = parser.parse(markdown);
+ WordCountVisitor visitor = new WordCountVisitor();
+ node.accept(visitor);
+ return visitor.wordCount;
+
+ }
+
+ public static String htmlToMarkDown(String htmlHeading) {
+ Heading heading = new Heading();
+ heading.setLevel(2);
+
+ heading.appendChild(new Text(htmlHeading));
+ Document document = new Document();
+ document.appendChild(heading);
+
+ MarkdownRenderer renderer = MarkdownRenderer.builder()
+ .build();
+ return renderer.render(document);
+ }
+
+ public static String changingHtmlAttribute(String source) {
+ Parser parser = Parser.builder()
+ .build();
+ Node node = parser.parse(source);
+ HtmlRenderer renderer = HtmlRenderer.builder()
+ .attributeProviderFactory(context -> new ImageAttributeProvider())
+ .build();
+
+ return renderer.render(node);
+ }
+
+ public static String customizingHtmlRendering(String source) {
+ Parser parser = Parser.builder()
+ .build();
+ Node node = parser.parse(source);
+ HtmlRenderer renderer = HtmlRenderer.builder()
+ .nodeRendererFactory(IndentedCodeBlockNodeRenderer::new)
+ .build();
+
+ return renderer.render(node);
+ }
+
+}
diff --git a/libraries-formatting/src/main/java/com/baeldung/commonmark/ImageAttributeProvider.java b/libraries-formatting/src/main/java/com/baeldung/commonmark/ImageAttributeProvider.java
new file mode 100644
index 000000000000..79ae5cb0cd73
--- /dev/null
+++ b/libraries-formatting/src/main/java/com/baeldung/commonmark/ImageAttributeProvider.java
@@ -0,0 +1,17 @@
+package com.baeldung.commonmark;
+
+import java.util.Map;
+
+import org.commonmark.node.Image;
+import org.commonmark.node.Node;
+import org.commonmark.renderer.html.AttributeProvider;
+
+public class ImageAttributeProvider implements AttributeProvider {
+
+ @Override
+ public void setAttributes(Node node, String tagName, Map attributes) {
+ if (node instanceof Image) {
+ attributes.put("class", "border");
+ }
+ }
+}
diff --git a/libraries-formatting/src/main/java/com/baeldung/commonmark/IndentedCodeBlockNodeRenderer.java b/libraries-formatting/src/main/java/com/baeldung/commonmark/IndentedCodeBlockNodeRenderer.java
new file mode 100644
index 000000000000..6dfba899bdc6
--- /dev/null
+++ b/libraries-formatting/src/main/java/com/baeldung/commonmark/IndentedCodeBlockNodeRenderer.java
@@ -0,0 +1,34 @@
+package com.baeldung.commonmark;
+
+import java.util.Set;
+
+import org.commonmark.node.IndentedCodeBlock;
+import org.commonmark.node.Node;
+import org.commonmark.renderer.NodeRenderer;
+import org.commonmark.renderer.html.HtmlNodeRendererContext;
+import org.commonmark.renderer.html.HtmlWriter;
+
+public class IndentedCodeBlockNodeRenderer implements NodeRenderer {
+
+ private final HtmlWriter html;
+
+ public IndentedCodeBlockNodeRenderer(HtmlNodeRendererContext context) {
+ this.html = context.getWriter();
+ }
+
+ @Override
+ public Set> getNodeTypes() {
+ return Set.of(IndentedCodeBlock.class);
+ }
+
+ @Override
+ public void render(Node node) {
+ IndentedCodeBlock codeBlock = (IndentedCodeBlock) node;
+ html.line();
+ html.tag("pre");
+ html.text(codeBlock.getLiteral());
+ html.tag("/pre");
+ html.line();
+
+ }
+}
diff --git a/libraries-formatting/src/main/java/com/baeldung/commonmark/WordCountVisitor.java b/libraries-formatting/src/main/java/com/baeldung/commonmark/WordCountVisitor.java
new file mode 100644
index 000000000000..4350f894be77
--- /dev/null
+++ b/libraries-formatting/src/main/java/com/baeldung/commonmark/WordCountVisitor.java
@@ -0,0 +1,18 @@
+package com.baeldung.commonmark;
+
+import org.commonmark.node.AbstractVisitor;
+import org.commonmark.node.Text;
+
+public class WordCountVisitor extends AbstractVisitor {
+
+ int wordCount = 0;
+
+ @Override
+ public void visit(Text text) {
+ wordCount += text.getLiteral().split("\\w+").length;
+ visitChildren(text);
+ }
+
+
+
+}
diff --git a/libraries-formatting/src/test/java/com/baeldung/commonmark/CommonMarkUsageUnitTest.java b/libraries-formatting/src/test/java/com/baeldung/commonmark/CommonMarkUsageUnitTest.java
new file mode 100644
index 000000000000..5a892f78263d
--- /dev/null
+++ b/libraries-formatting/src/test/java/com/baeldung/commonmark/CommonMarkUsageUnitTest.java
@@ -0,0 +1,48 @@
+package com.baeldung.commonmark;
+
+import static com.baeldung.commonmark.CommonMarkUsage.changingHtmlAttribute;
+import static com.baeldung.commonmark.CommonMarkUsage.customizingHtmlRendering;
+import static com.baeldung.commonmark.CommonMarkUsage.htmlToMarkDown;
+import static com.baeldung.commonmark.CommonMarkUsage.markDownToHtml;
+import static com.baeldung.commonmark.CommonMarkUsage.processParsedNode;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class CommonMarkUsageUnitTest {
+
+ @Test
+ void givenMarkdownInput_whenConvertingToHtml_thenReturnRenderedHtml() {
+ String html = markDownToHtml("Welcome to *Baeldung*");
+
+ assertEquals("Welcome to Baeldung
\n", html);
+ }
+
+ @Test
+ void givenMarkdownInput_whenProcessingParsedNode_thenReturnWordCount() {
+ int wordCount = processParsedNode("Welcome to *Baeldung*");
+
+ assertEquals(3, wordCount);
+ }
+
+ @Test
+ void givenHeadingText_whenConvertingToMarkdown_thenReturnMarkdownHeading() {
+ String markdown = htmlToMarkDown("Java Tutorial");
+
+ assertEquals("## Java Tutorial\n", markdown);
+ }
+
+ @Test
+ void givenImageMarkdown_whenRenderingHtml_thenAddCustomClassAttribute() {
+ String html = changingHtmlAttribute("");
+
+ assertEquals("
\n", html);
+ }
+
+ @Test
+ void givenIndentedCodeBlock_whenRenderingHtml_thenUseCustomNodeRenderer() {
+ String html = customizingHtmlRendering("Example:\n\n code");
+
+ assertEquals("Example:
\ncode\n
\n", html);
+ }
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 54d1b360bcea..49903795cfe8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -719,6 +719,7 @@
libraries-data-io-2
libraries-data-mariadb4j
libraries-files
+ libraries-formatting
libraries-http
libraries-http-2
libraries-http-3
@@ -1197,6 +1198,7 @@
libraries-data-io-2
libraries-data-mariadb4j
libraries-files
+ libraries-formatting
libraries-http
libraries-http-2
libraries-http-3