From b6135ecc5687f5ccaaf51fa3f41c5be96fa3dd71 Mon Sep 17 00:00:00 2001
From: shenliming <348515494@qq.com>
Date: Fri, 7 Apr 2023 10:49:34 +0800
Subject: [PATCH] replace commonMark to flexMark

---
 app-sample/build.gradle                       |  53 +-
 app-sample/samples.json                       |  83 --
 app-sample/src/main/AndroidManifest.xml       |   6 +-
 .../app/samples/AdditionalSpacingSample.java  |   2 +-
 .../AllBlocksNoForcedNewLineSample.java       |   2 +-
 .../app/samples/BlockHandlerSample.java       |   2 +-
 .../app/samples/ChangeBulletSpanSample.java   |   3 +-
 .../app/samples/CopyCodeBlockSample.kt        | 142 +--
 .../app/samples/CustomExtensionSample.java    | 436 ---------
 .../app/samples/DelimiterProcessorSample.java |  83 --
 .../app/samples/DisableNodeSample.java        |   2 +-
 .../app/samples/EnabledBlockTypesSample.kt    |  45 -
 .../app/samples/ExcludeFromParsingSample.kt   |   2 +-
 .../GithubUserIssueInlineParsingSample.java   | 110 ---
 .../GithubUserIssueOnTextAddedSample.java     |   2 +-
 .../app/samples/HeadingColorSample.java       |   2 +-
 .../HeadingNoSpaceBlockHandlerSample.java     |   4 +-
 .../app/samples/HeadingNoSpaceSample.java     |   2 +-
 .../samples/InlinePluginNoDefaultsSample.java |  35 -
 .../app/samples/LetterOrderedListSample.java  |   8 +-
 .../samples/LinkRemoveUnderlineSample.java    |   2 +-
 .../markwon/app/samples/LinkTitleSample.java  |   2 +-
 .../markwon/app/samples/NoParsingSample.java  |  49 --
 .../app/samples/ParagraphSpanStyle.java       |   2 +-
 .../markwon/app/samples/RecyclerSample.java   |   6 +-
 .../ThematicBreakBottomMarginSample.java      |   4 +-
 .../app/samples/ToastDynamicContentSample.kt  |   2 +-
 .../app/samples/basics/SimpleWalkthrough.kt   |   2 +-
 .../InlineParsingTooltipSample.java           |   9 +-
 .../app/samples/latex/LatexLegacySample.java  |  37 -
 .../app/samples/latex/LatexOmegaSample.java   |   2 -
 .../app/samples/latex/LatexThemeSample.java   |   2 -
 .../notification/RemoteViewsSample.java       |  14 +-
 .../parser/CustomHeadingParserSample.kt       |  47 -
 .../plugins/TableOfContentsSample.java        | 156 ----
 .../app/samples/table/TableLatexSample.java   |   2 -
 .../tasklist/TaskListMutateNestedSample.kt    | 157 ----
 .../tasklist/TaskListMutateSample.java        |   3 +-
 build.gradle                                  |  29 +-
 gradle.properties                             |  20 +-
 gradle/publishAllToMavenLocal.sh              |  20 +
 gradle/publishMaven.gradle                    | 240 +++++
 gradle/wrapper/gradle-wrapper.properties      |   2 +-
 markwon-core/build.gradle                     |   6 +-
 .../noties/markwon/AbstractMarkwonPlugin.java |   4 +-
 .../io/noties/markwon/BlockHandlerDef.java    |   2 +-
 .../main/java/io/noties/markwon/Markwon.java  |   2 +-
 .../io/noties/markwon/MarkwonBuilderImpl.java |   2 +-
 .../java/io/noties/markwon/MarkwonImpl.java   |  12 +-
 .../java/io/noties/markwon/MarkwonPlugin.java |   4 +-
 .../io/noties/markwon/MarkwonReducer.java     |   6 +-
 .../noties/markwon/MarkwonSpansFactory.java   |   2 +-
 .../markwon/MarkwonSpansFactoryImpl.java      |   2 +-
 .../io/noties/markwon/MarkwonVisitor.java     |  21 +-
 .../io/noties/markwon/MarkwonVisitorImpl.java | 191 ++--
 .../markwon/SoftBreakAddsNewLinePlugin.java   |   2 +-
 .../io/noties/markwon/core/CorePlugin.java    |  55 +-
 .../markwon/core/SimpleBlockNodeVisitor.java  |   2 +-
 .../markwon/syntax/SyntaxHighlight.java       |   1 +
 .../io/noties/markwon/utils/DumpNodes.java    |   9 +-
 .../io/noties/markwon/utils/ParserUtils.java  |   2 +-
 markwon-editor/build.gradle                   |   3 +-
 markwon-ext-latex/build.gradle                |   4 +-
 .../markwon/ext/latex/JLatexMathBlock.java    |  16 -
 .../ext/latex/JLatexMathBlockParser.java      | 119 ---
 .../latex/JLatexMathBlockParserLegacy.java    |  82 --
 .../ext/latex/JLatexMathInlineProcessor.java  |  36 -
 .../markwon/ext/latex/JLatexMathNode.java     |  19 -
 .../markwon/ext/latex/JLatexMathPlugin.java   |  99 +--
 .../ext/latex/JLatexMathBlockParserTest.java  | 173 ----
 .../ext/latex/JLatexMathPluginTest.java       | 230 -----
 markwon-ext-strikethrough/build.gradle        |   5 +-
 .../strikethrough/StrikethroughPlugin.java    |  10 +-
 markwon-ext-tables/build.gradle               |  11 +-
 .../io/noties/markwon/ext/tables/Table.java   |  86 +-
 .../markwon/ext/tables/TablePlugin.java       |  16 +-
 .../markwon/ext/tables/TableVisitor.java      |  28 +
 markwon-ext-tasklist/build.gradle             |   3 +-
 .../markwon/ext/tasklist/TaskListItem.java    |  30 -
 .../markwon/ext/tasklist/TaskListPlugin.java  |  22 +-
 .../ext/tasklist/TaskListPostProcessor.java   |  82 --
 markwon-html/build.gradle                     |   2 +-
 .../io/noties/markwon/html/HtmlPlugin.java    |  10 +-
 .../html/jsoup/nodes/CommonMarkEntities.java  |   2 +-
 .../markwon/html/tag/BlockquoteHandler.java   |   2 +-
 .../markwon/html/tag/EmphasisHandler.java     |   2 +-
 .../markwon/html/tag/HeadingHandler.java      |   2 +-
 .../noties/markwon/html/tag/ImageHandler.java |   2 +-
 .../noties/markwon/html/tag/LinkHandler.java  |   2 +-
 .../noties/markwon/html/tag/ListHandler.java  |   2 +-
 .../markwon/html/tag/StrikeHandler.java       |   4 +-
 .../html/tag/StrongEmphasisHandler.java       |   2 +-
 markwon-image-coil/build.gradle               |   1 +
 .../markwon/image/coil/CoilImagesPlugin.java  |   2 +-
 markwon-image-glide/build.gradle              |   3 +-
 .../image/glide/GlideImagesPlugin.java        |   3 +-
 markwon-image-picasso/build.gradle            |   3 +-
 .../image/picasso/PicassoImagesPlugin.java    |   3 +-
 markwon-image/build.gradle                    |   3 +-
 .../io/noties/markwon/image/ImagesPlugin.java |   2 +-
 markwon-inline-parser/README.md               |  16 -
 markwon-inline-parser/build.gradle            |  27 -
 markwon-inline-parser/gradle.properties       |   4 -
 .../src/main/AndroidManifest.xml              |   1 -
 .../inlineparser/AutolinkInlineProcessor.java |  44 -
 .../BackslashInlineProcessor.java             |  35 -
 .../BackticksInlineProcessor.java             |  56 --
 .../inlineparser/BangInlineProcessor.java     |  35 -
 .../CloseBracketInlineProcessor.java          | 140 ---
 .../inlineparser/EntityInlineProcessor.java   |  32 -
 .../inlineparser/HtmlInlineProcessor.java     |  40 -
 .../inlineparser/InlineParserUtils.java       |  77 --
 .../markwon/inlineparser/InlineProcessor.java | 141 ---
 .../inlineparser/MarkwonInlineParser.java     | 831 ------------------
 .../MarkwonInlineParserContext.java           |  64 --
 .../MarkwonInlineParserPlugin.java            |  59 --
 .../inlineparser/NewLineInlineProcessor.java  |  48 -
 .../OpenBracketInlineProcessor.java           |  30 -
 .../StaggeredDelimiterProcessor.java          |  75 --
 .../inlineparser/InlineParserSpecTest.java    |  25 -
 markwon-linkify/build.gradle                  |   1 +
 .../noties/markwon/linkify/LinkifyPlugin.java |   2 +-
 markwon-recycler-table/build.gradle           |   3 +-
 .../markwon/recycler/table/TableEntry.java    |   2 +-
 .../recycler/table/TableEntryPlugin.java      |   5 +-
 markwon-recycler/build.gradle                 |   3 +-
 .../markwon/recycler/MarkwonAdapter.java      |   2 +-
 .../markwon/recycler/MarkwonAdapterImpl.java  |   2 +-
 .../noties/markwon/recycler/SimpleEntry.java  |   2 +-
 markwon-simple-ext/build.gradle               |   3 +-
 .../markwon/simple/ext/SimpleExtBuilder.java  |   3 +-
 .../ext/SimpleExtDelimiterProcessor.java      |  41 +-
 .../markwon/simple/ext/SimpleExtNode.java     |  19 +-
 .../markwon/simple/ext/SimpleExtPlugin.java   |   4 +-
 markwon-syntax-highlight/build.gradle         |   1 +
 markwon-test-span/build.gradle                |   2 +-
 sample-utils/processor/build.gradle           |   3 -
 settings.gradle                               |   1 -
 138 files changed, 815 insertions(+), 4348 deletions(-)
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/CustomExtensionSample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/DelimiterProcessorSample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/EnabledBlockTypesSample.kt
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/InlinePluginNoDefaultsSample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/NoParsingSample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexLegacySample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/parser/CustomHeadingParserSample.kt
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/plugins/TableOfContentsSample.java
 delete mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateNestedSample.kt
 create mode 100755 gradle/publishAllToMavenLocal.sh
 create mode 100644 gradle/publishMaven.gradle
 delete mode 100644 markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java
 delete mode 100644 markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java
 delete mode 100644 markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParserLegacy.java
 delete mode 100644 markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathInlineProcessor.java
 delete mode 100644 markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathNode.java
 delete mode 100644 markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathBlockParserTest.java
 delete mode 100644 markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathPluginTest.java
 create mode 100644 markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableVisitor.java
 delete mode 100644 markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java
 delete mode 100644 markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPostProcessor.java
 delete mode 100644 markwon-inline-parser/README.md
 delete mode 100644 markwon-inline-parser/build.gradle
 delete mode 100644 markwon-inline-parser/gradle.properties
 delete mode 100644 markwon-inline-parser/src/main/AndroidManifest.xml
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AutolinkInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackslashInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackticksInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BangInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/CloseBracketInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/EntityInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/HtmlInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineParserUtils.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserContext.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserPlugin.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/NewLineInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/OpenBracketInlineProcessor.java
 delete mode 100644 markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/StaggeredDelimiterProcessor.java
 delete mode 100644 markwon-inline-parser/src/test/java/io/noties/markwon/inlineparser/InlineParserSpecTest.java

diff --git a/app-sample/build.gradle b/app-sample/build.gradle
index bfd97997..4d7acf82 100644
--- a/app-sample/build.gradle
+++ b/app-sample/build.gradle
@@ -44,12 +44,8 @@ android {
     }
 
     compileOptions {
-        targetCompatibility JavaVersion.VERSION_1_8
-        sourceCompatibility JavaVersion.VERSION_1_8
-    }
-
-    kotlinOptions {
-        jvmTarget = "1.8"
+        targetCompatibility JavaVersion.VERSION_11
+        sourceCompatibility JavaVersion.VERSION_11
     }
 
     sourceSets {
@@ -58,48 +54,6 @@ android {
         }
     }
 
-    // do not sign in CI
-    if (!project.hasProperty('CI')) {
-        signingConfigs {
-            config {
-
-                final def keystoreFile = project.file('keystore.jks')
-                final def keystoreFilePassword = 'MARKWON_KEYSTORE_FILE_PASSWORD'
-                final def keystoreAlias = 'MARKWON_KEY_ALIAS'
-                final def keystoreAliasPassword = 'MARKWON_KEY_ALIAS_PASSWORD'
-
-                final def properties = [
-                        keystoreFilePassword,
-                        keystoreAlias,
-                        keystoreAliasPassword
-                ]
-
-                if (!keystoreFile.exists()) {
-                    throw new IllegalStateException("No '${keystoreFile.name}' file is found.")
-                }
-
-                final def missingProperties = properties.findAll { !project.hasProperty(it) }
-                if (!missingProperties.isEmpty()) {
-                    throw new IllegalStateException("Missing required signing properties: $missingProperties")
-                }
-
-                storeFile keystoreFile
-                storePassword project[keystoreFilePassword]
-
-                keyAlias project[keystoreAlias]
-                keyPassword project[keystoreAliasPassword]
-            }
-        }
-
-        buildTypes {
-            debug {
-                signingConfig signingConfigs.config
-            }
-            release {
-                signingConfig signingConfigs.config
-            }
-        }
-    }
 }
 
 kapt {
@@ -122,7 +76,7 @@ dependencies {
         kapt it['prism4j-bundler']
     }
 
-    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
 
     implementation project(':markwon-core')
     implementation project(':markwon-editor')
@@ -132,7 +86,6 @@ dependencies {
     implementation project(':markwon-ext-tasklist')
     implementation project(':markwon-html')
     implementation project(':markwon-image')
-    implementation project(':markwon-inline-parser')
     implementation project(':markwon-linkify')
     implementation project(':markwon-recycler')
     implementation project(':markwon-recycler-table')
diff --git a/app-sample/samples.json b/app-sample/samples.json
index 1b4c5275..9082b7e3 100644
--- a/app-sample/samples.json
+++ b/app-sample/samples.json
@@ -651,18 +651,6 @@
       "parsing"
     ]
   },
-  {
-    "javaClassName": "io.noties.markwon.app.samples.DelimiterProcessorSample",
-    "id": "20200630194017",
-    "title": "Custom delimiter processor",
-    "description": "Custom parsing delimiter processor with `?` character",
-    "artifacts": [
-      "CORE"
-    ],
-    "tags": [
-      "parsing"
-    ]
-  },
   {
     "javaClassName": "io.noties.markwon.app.samples.html.HtmlDisableSanitizeSample",
     "id": "20200630171424",
@@ -957,31 +945,6 @@
       "editor"
     ]
   },
-  {
-    "javaClassName": "io.noties.markwon.app.samples.NoParsingSample",
-    "id": "20200629171212",
-    "title": "No parsing",
-    "description": "All commonmark parsing is disabled (both inlines and blocks)",
-    "artifacts": [
-      "CORE"
-    ],
-    "tags": [
-      "parsing",
-      "rendering"
-    ]
-  },
-  {
-    "javaClassName": "io.noties.markwon.app.samples.InlinePluginNoDefaultsSample",
-    "id": "20200629170857",
-    "title": "Inline parsing without defaults",
-    "description": "Configure inline parser plugin to **not** have any **inline** parsing",
-    "artifacts": [
-      "INLINE_PARSER"
-    ],
-    "tags": [
-      "parsing"
-    ]
-  },
   {
     "javaClassName": "io.noties.markwon.app.samples.editor.EditorNewLineContinuationSample",
     "id": "20200629170348",
@@ -1076,23 +1039,6 @@
       "editor"
     ]
   },
-  {
-    "javaClassName": "io.noties.markwon.app.samples.CustomExtensionSample",
-    "id": "20200629163248",
-    "title": "Custom extension",
-    "description": "Custom extension that adds an icon from resources and renders it as image with `@ic-name` syntax",
-    "artifacts": [
-      "CORE"
-    ],
-    "tags": [
-      "parsing",
-      "plugin",
-      "rendering",
-      "image",
-      "extension",
-      "span"
-    ]
-  },
   {
     "javaClassName": "io.noties.markwon.app.samples.GithubUserIssueOnTextAddedSample",
     "id": "20200629162024",
@@ -1107,21 +1053,6 @@
       "textAddedListener"
     ]
   },
-  {
-    "javaClassName": "io.noties.markwon.app.samples.GithubUserIssueInlineParsingSample",
-    "id": "20200629162023",
-    "title": "User mention and issue (via text)",
-    "description": "Github-like user mention and issue rendering via `CorePlugin.OnTextAddedListener`",
-    "artifacts": [
-      "CORE",
-      "INLINE_PARSER"
-    ],
-    "tags": [
-      "parsing",
-      "rendering",
-      "textAddedListener"
-    ]
-  },
   {
     "javaClassName": "io.noties.markwon.app.samples.ReadMorePluginSample",
     "id": "20200629161505",
@@ -1410,20 +1341,6 @@
       "defaults"
     ]
   },
-  {
-    "javaClassName": "io.noties.markwon.app.samples.EnabledBlockTypesSample",
-    "id": "20200627075012",
-    "title": "Enabled markdown blocks",
-    "description": "Modify/inspect enabled by `CorePlugin` block types. Disable quotes or other blocks from being parsed",
-    "artifacts": [
-      "CORE"
-    ],
-    "tags": [
-      "parsing",
-      "block",
-      "plugin"
-    ]
-  },
   {
     "javaClassName": "io.noties.markwon.app.samples.ToastDynamicContentSample",
     "id": "20200627074017",
diff --git a/app-sample/src/main/AndroidManifest.xml b/app-sample/src/main/AndroidManifest.xml
index 0c265b10..70511bdd 100644
--- a/app-sample/src/main/AndroidManifest.xml
+++ b/app-sample/src/main/AndroidManifest.xml
@@ -15,7 +15,9 @@
         android:theme="@style/AppTheme"
         tools:ignore="AllowBackup,GoogleAppIndexingWarning">
 
-        <activity android:name=".sample.MainActivity">
+        <activity
+            android:name=".sample.MainActivity"
+            android:exported="true">
             <!-- launcher intent -->
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -42,7 +44,7 @@
                     android:host="noties.io"
                     android:scheme="https" />
 
-                <data android:pathPrefix="/Markwon/app"/>
+                <data android:pathPrefix="/Markwon/app" />
 
                 <data android:pathPattern="sample/.*" />
                 <data android:pathPattern="search" />
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/AdditionalSpacingSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/AdditionalSpacingSample.java
index 3b263846..a4ab110b 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/AdditionalSpacingSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/AdditionalSpacingSample.java
@@ -2,7 +2,7 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Heading;
+import com.vladsch.flexmark.ast.Heading;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/AllBlocksNoForcedNewLineSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/AllBlocksNoForcedNewLineSample.java
index cfa03316..b5427175 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/AllBlocksNoForcedNewLineSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/AllBlocksNoForcedNewLineSample.java
@@ -2,7 +2,7 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.BlockHandlerDef;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/BlockHandlerSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/BlockHandlerSample.java
index bfb066ac..a7df79c4 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/BlockHandlerSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/BlockHandlerSample.java
@@ -2,7 +2,7 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/ChangeBulletSpanSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/ChangeBulletSpanSample.java
index 373053e8..294b7b3b 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/ChangeBulletSpanSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/ChangeBulletSpanSample.java
@@ -4,7 +4,8 @@ import android.text.style.BulletSpan;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.ListItem;
+import com.vladsch.flexmark.ast.ListItem;
+
 
 import io.noties.debug.Debug;
 import io.noties.markwon.AbstractMarkwonPlugin;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt
index 9860111a..7b224e47 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt
@@ -10,6 +10,7 @@ import android.text.style.ClickableSpan
 import android.text.style.LeadingMarginSpan
 import android.view.View
 import android.widget.TextView
+import com.vladsch.flexmark.ast.FencedCodeBlock
 import io.noties.debug.Debug
 import io.noties.markwon.AbstractMarkwonPlugin
 import io.noties.markwon.Markwon
@@ -20,19 +21,18 @@ import io.noties.markwon.sample.annotations.MarkwonArtifact
 import io.noties.markwon.sample.annotations.MarkwonSampleInfo
 import io.noties.markwon.sample.annotations.Tag
 import io.noties.markwon.utils.LeadingMarginUtils
-import org.commonmark.node.FencedCodeBlock
 
 @MarkwonSampleInfo(
-        id = "20210315112847",
-        title = "Copy code block",
-        description = "Copy contents of fenced code blocks",
-        artifacts = [MarkwonArtifact.CORE],
-        tags = [Tag.rendering, Tag.block, Tag.spanFactory, Tag.span]
+  id = "20210315112847",
+  title = "Copy code block",
+  description = "Copy contents of fenced code blocks",
+  artifacts = [MarkwonArtifact.CORE],
+  tags = [Tag.rendering, Tag.block, Tag.spanFactory, Tag.span]
 )
 class CopyCodeBlockSample : MarkwonTextViewSample() {
 
-    override fun render() {
-        val md = """
+  override fun render() {
+    val md = """
             # Hello code blocks!
             ```java
             final int i = 0;
@@ -43,77 +43,77 @@ class CopyCodeBlockSample : MarkwonTextViewSample() {
             bye bye!
         """.trimIndent()
 
-        val markwon = Markwon.builder(context)
-                .usePlugin(object : AbstractMarkwonPlugin() {
-                    override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
-                        builder.appendFactory(FencedCodeBlock::class.java) { _, _ ->
-                            CopyContentsSpan()
-                        }
-                        builder.appendFactory(FencedCodeBlock::class.java) { _, _ ->
-                            CopyIconSpan(context.getDrawable(R.drawable.ic_code_white_24dp)!!)
-                        }
-                    }
-                })
-                .build()
+    val markwon = Markwon.builder(context)
+      .usePlugin(object : AbstractMarkwonPlugin() {
+        override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
+          builder.appendFactory(FencedCodeBlock::class.java) { _, _ ->
+            CopyContentsSpan()
+          }
+          builder.appendFactory(FencedCodeBlock::class.java) { _, _ ->
+            CopyIconSpan(context.getDrawable(R.drawable.ic_code_white_24dp)!!)
+          }
+        }
+      })
+      .build()
 
-        markwon.setMarkdown(textView, md)
+    markwon.setMarkdown(textView, md)
+  }
+
+  class CopyContentsSpan : ClickableSpan() {
+    override fun onClick(widget: View) {
+      val spanned = (widget as? TextView)?.text as? Spanned ?: return
+      val start = spanned.getSpanStart(this)
+      val end = spanned.getSpanEnd(this)
+      // by default code blocks have new lines before and after content
+      val contents = spanned.subSequence(start, end).toString().trim()
+      // copy code here
+      Debug.i(contents)
     }
 
-    class CopyContentsSpan : ClickableSpan() {
-        override fun onClick(widget: View) {
-            val spanned = (widget as? TextView)?.text as? Spanned ?: return
-            val start = spanned.getSpanStart(this)
-            val end = spanned.getSpanEnd(this)
-            // by default code blocks have new lines before and after content
-            val contents = spanned.subSequence(start, end).toString().trim()
-            // copy code here
-            Debug.i(contents)
-        }
+    override fun updateDrawState(ds: TextPaint) {
+      // do not apply link styling
+    }
+  }
 
-        override fun updateDrawState(ds: TextPaint) {
-            // do not apply link styling
-        }
+  class CopyIconSpan(val icon: Drawable) : LeadingMarginSpan {
+
+    init {
+      if (icon.bounds.isEmpty) {
+        icon.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight)
+      }
     }
 
-    class CopyIconSpan(val icon: Drawable) : LeadingMarginSpan {
+    override fun getLeadingMargin(first: Boolean): Int = 0
 
-        init {
-            if (icon.bounds.isEmpty) {
-                icon.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight)
-            }
-        }
+    override fun drawLeadingMargin(
+      c: Canvas,
+      p: Paint,
+      x: Int,
+      dir: Int,
+      top: Int,
+      baseline: Int,
+      bottom: Int,
+      text: CharSequence,
+      start: Int,
+      end: Int,
+      first: Boolean,
+      layout: Layout
+    ) {
 
-        override fun getLeadingMargin(first: Boolean): Int = 0
+      // called for each line of text, we are interested only in first one
+      if (!LeadingMarginUtils.selfStart(start, text, this)) return
 
-        override fun drawLeadingMargin(
-                c: Canvas,
-                p: Paint,
-                x: Int,
-                dir: Int,
-                top: Int,
-                baseline: Int,
-                bottom: Int,
-                text: CharSequence,
-                start: Int,
-                end: Int,
-                first: Boolean,
-                layout: Layout
-        ) {
-
-            // called for each line of text, we are interested only in first one
-            if (!LeadingMarginUtils.selfStart(start, text, this)) return
-
-            val save = c.save()
-            try {
-                // horizontal position for icon
-                val w = icon.bounds.width().toFloat()
-                // minus quarter width as padding
-                val left = layout.width - w - (w / 4F)
-                c.translate(left, top.toFloat())
-                icon.draw(c)
-            } finally {
-                c.restoreToCount(save)
-            }
-        }
+      val save = c.save()
+      try {
+        // horizontal position for icon
+        val w = icon.bounds.width().toFloat()
+        // minus quarter width as padding
+        val left = layout.width - w - (w / 4F)
+        c.translate(left, top.toFloat())
+        icon.draw(c)
+      } finally {
+        c.restoreToCount(save)
+      }
     }
+  }
 }
\ No newline at end of file
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/CustomExtensionSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/CustomExtensionSample.java
deleted file mode 100644
index 484e7f92..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/CustomExtensionSample.java
+++ /dev/null
@@ -1,436 +0,0 @@
-package io.noties.markwon.app.samples;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.text.style.ReplacementSpan;
-
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.commonmark.node.CustomNode;
-import org.commonmark.node.Delimited;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-import org.commonmark.parser.Parser;
-import org.commonmark.parser.delimiter.DelimiterProcessor;
-import org.commonmark.parser.delimiter.DelimiterRun;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import io.noties.markwon.AbstractMarkwonPlugin;
-import io.noties.markwon.Markwon;
-import io.noties.markwon.MarkwonVisitor;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200629163248",
-  title = "Custom extension",
-  description = "Custom extension that adds an " +
-    "icon from resources and renders it as image with " +
-    "`@ic-name` syntax",
-  artifacts = MarkwonArtifact.CORE,
-  tags = {Tag.parsing, Tag.rendering, Tag.plugin, Tag.image, Tag.extension, Tag.span}
-)
-public class CustomExtensionSample extends MarkwonTextViewSample {
-  @Override
-  public void render() {
-    final String md = "" +
-      "# Hello! @ic-android-black-24\n\n" +
-      "" +
-      "Home 36 black: @ic-home-black-36\n\n" +
-      "" +
-      "Memory 48 black: @ic-memory-black-48\n\n" +
-      "" +
-      "### I AM ANOTHER HEADER\n\n" +
-      "" +
-      "Sentiment Satisfied 64 red: @ic-sentiment_satisfied-red-64" +
-      "";
-
-    // note that we haven't registered CorePlugin, as it's the only one that can be
-    // implicitly deducted and added automatically. All other plugins require explicit
-    // `usePlugin` call
-    final Markwon markwon = Markwon.builder(context)
-      .usePlugin(IconPlugin.create(IconSpanProvider.create(context, 0)))
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
-
-class IconPlugin extends AbstractMarkwonPlugin {
-
-  @NonNull
-  public static IconPlugin create(@NonNull IconSpanProvider iconSpanProvider) {
-    return new IconPlugin(iconSpanProvider);
-  }
-
-  private final IconSpanProvider iconSpanProvider;
-
-  IconPlugin(@NonNull IconSpanProvider iconSpanProvider) {
-    this.iconSpanProvider = iconSpanProvider;
-  }
-
-  @Override
-  public void configureParser(@NonNull Parser.Builder builder) {
-    builder.customDelimiterProcessor(IconProcessor.create());
-  }
-
-  @Override
-  public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
-    builder.on(IconNode.class, (visitor, iconNode) -> {
-
-      final String name = iconNode.name();
-      final String color = iconNode.color();
-      final String size = iconNode.size();
-
-      if (!TextUtils.isEmpty(name)
-        && !TextUtils.isEmpty(color)
-        && !TextUtils.isEmpty(size)) {
-
-        final int length = visitor.length();
-
-        visitor.builder().append(name);
-        visitor.setSpans(length, iconSpanProvider.provide(name, color, size));
-        visitor.builder().append(' ');
-      }
-    });
-  }
-
-  @NonNull
-  @Override
-  public String processMarkdown(@NonNull String markdown) {
-    return IconProcessor.prepare(markdown);
-  }
-}
-
-abstract class IconSpanProvider {
-
-  @SuppressWarnings("SameParameterValue")
-  @NonNull
-  public static IconSpanProvider create(@NonNull Context context, @DrawableRes int fallBack) {
-    return new Impl(context, fallBack);
-  }
-
-
-  @NonNull
-  public abstract IconSpan provide(@NonNull String name, @NonNull String color, @NonNull String size);
-
-
-  private static class Impl extends IconSpanProvider {
-
-    private final Context context;
-    private final Resources resources;
-    private final int fallBack;
-
-    Impl(@NonNull Context context, @DrawableRes int fallBack) {
-      this.context = context;
-      this.resources = context.getResources();
-      this.fallBack = fallBack;
-    }
-
-    @NonNull
-    @Override
-    public IconSpan provide(@NonNull String name, @NonNull String color, @NonNull String size) {
-      final String resName = iconName(name, color, size);
-      int resId = resources.getIdentifier(resName, "drawable", context.getPackageName());
-      if (resId == 0) {
-        resId = fallBack;
-      }
-      return new IconSpan(getDrawable(resId), IconSpan.ALIGN_CENTER);
-    }
-
-
-    @NonNull
-    private static String iconName(@NonNull String name, @NonNull String color, @NonNull String size) {
-      return "ic_" + name + "_" + color + "_" + size + "dp";
-    }
-
-    @NonNull
-    private Drawable getDrawable(int resId) {
-      //noinspection ConstantConditions
-      return context.getDrawable(resId);
-    }
-  }
-}
-
-class IconSpan extends ReplacementSpan {
-
-  @IntDef({ALIGN_BOTTOM, ALIGN_BASELINE, ALIGN_CENTER})
-  @Retention(RetentionPolicy.CLASS)
-  @interface Alignment {
-  }
-
-  public static final int ALIGN_BOTTOM = 0;
-  public static final int ALIGN_BASELINE = 1;
-  public static final int ALIGN_CENTER = 2; // will only center if drawable height is less than text line height
-
-
-  private final Drawable drawable;
-
-  private final int alignment;
-
-  public IconSpan(@NonNull Drawable drawable, @Alignment int alignment) {
-    this.drawable = drawable;
-    this.alignment = alignment;
-    if (drawable.getBounds().isEmpty()) {
-      drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
-    }
-  }
-
-  @Override
-  public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
-
-    final Rect rect = drawable.getBounds();
-
-    if (fm != null) {
-      fm.ascent = -rect.bottom;
-      fm.descent = 0;
-
-      fm.top = fm.ascent;
-      fm.bottom = 0;
-    }
-
-    return rect.right;
-  }
-
-  @Override
-  public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
-
-    final int b = bottom - drawable.getBounds().bottom;
-
-    final int save = canvas.save();
-    try {
-      final int translationY;
-      if (ALIGN_CENTER == alignment) {
-        translationY = b - ((bottom - top - drawable.getBounds().height()) / 2);
-      } else if (ALIGN_BASELINE == alignment) {
-        translationY = b - paint.getFontMetricsInt().descent;
-      } else {
-        translationY = b;
-      }
-      canvas.translate(x, translationY);
-      drawable.draw(canvas);
-    } finally {
-      canvas.restoreToCount(save);
-    }
-  }
-}
-
-class IconProcessor implements DelimiterProcessor {
-
-  @NonNull
-  public static IconProcessor create() {
-    return new IconProcessor();
-  }
-
-  // ic-home-black-24
-  private static final Pattern PATTERN = Pattern.compile("ic-(\\w+)-(\\w+)-(\\d+)");
-
-  private static final String TO_FIND = IconNode.DELIMITER_STRING + "ic-";
-
-  /**
-   * Should be used when input string does not wrap icon definition with `@` from both ends.
-   * So, `@ic-home-white-24` would become `@ic-home-white-24@`. This way parsing is easier
-   * and more predictable (cannot specify multiple ending delimiters, as we would require them:
-   * space, newline, end of a document, and a lot of more)
-   *
-   * @param input to process
-   * @return processed string
-   * @see #prepare(StringBuilder)
-   */
-  @NonNull
-  public static String prepare(@NonNull String input) {
-    final StringBuilder builder = new StringBuilder(input);
-    prepare(builder);
-    return builder.toString();
-  }
-
-  public static void prepare(@NonNull StringBuilder builder) {
-
-    int start = builder.indexOf(TO_FIND);
-    int end;
-
-    while (start > -1) {
-
-      end = iconDefinitionEnd(start + TO_FIND.length(), builder);
-
-      // if we match our pattern, append `@` else ignore
-      if (iconDefinitionValid(builder.subSequence(start + 1, end))) {
-        builder.insert(end, '@');
-      }
-
-      // move to next
-      start = builder.indexOf(TO_FIND, end);
-    }
-  }
-
-  @Override
-  public char getOpeningCharacter() {
-    return IconNode.DELIMITER;
-  }
-
-  @Override
-  public char getClosingCharacter() {
-    return IconNode.DELIMITER;
-  }
-
-  @Override
-  public int getMinLength() {
-    return 1;
-  }
-
-  @Override
-  public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) {
-    return opener.length() >= 1 && closer.length() >= 1 ? 1 : 0;
-  }
-
-  @Override
-  public void process(Text opener, Text closer, int delimiterUse) {
-
-    final IconGroupNode iconGroupNode = new IconGroupNode();
-
-    final Node next = opener.getNext();
-
-    boolean handled = false;
-
-    // process only if we have exactly one Text node
-    if (next instanceof Text && next.getNext() == closer) {
-
-      final String text = ((Text) next).getLiteral();
-
-      if (!TextUtils.isEmpty(text)) {
-
-        // attempt to match
-        final Matcher matcher = PATTERN.matcher(text);
-        if (matcher.matches()) {
-          final IconNode iconNode = new IconNode(
-            matcher.group(1),
-            matcher.group(2),
-            matcher.group(3)
-          );
-          iconGroupNode.appendChild(iconNode);
-          next.unlink();
-          handled = true;
-        }
-      }
-    }
-
-    if (!handled) {
-
-      // restore delimiters if we didn't match
-
-      iconGroupNode.appendChild(new Text(IconNode.DELIMITER_STRING));
-
-      Node node;
-      for (Node tmp = opener.getNext(); tmp != null && tmp != closer; tmp = node) {
-        node = tmp.getNext();
-        // append a child anyway
-        iconGroupNode.appendChild(tmp);
-      }
-
-      iconGroupNode.appendChild(new Text(IconNode.DELIMITER_STRING));
-    }
-
-    opener.insertBefore(iconGroupNode);
-  }
-
-  private static int iconDefinitionEnd(int index, @NonNull StringBuilder builder) {
-
-    // all spaces, new lines, non-words or digits,
-
-    char c;
-
-    int end = -1;
-    for (int i = index; i < builder.length(); i++) {
-      c = builder.charAt(i);
-      if (Character.isWhitespace(c)
-        || !(Character.isLetterOrDigit(c) || c == '-' || c == '_')) {
-        end = i;
-        break;
-      }
-    }
-
-    if (end == -1) {
-      end = builder.length();
-    }
-
-    return end;
-  }
-
-  private static boolean iconDefinitionValid(@NonNull CharSequence cs) {
-    final Matcher matcher = PATTERN.matcher(cs);
-    return matcher.matches();
-  }
-}
-
-class IconNode extends CustomNode implements Delimited {
-
-  public static final char DELIMITER = '@';
-
-  public static final String DELIMITER_STRING = "" + DELIMITER;
-
-
-  private final String name;
-
-  private final String color;
-
-  private final String size;
-
-  public IconNode(@NonNull String name, @NonNull String color, @NonNull String size) {
-    this.name = name;
-    this.color = color;
-    this.size = size;
-  }
-
-  @NonNull
-  public String name() {
-    return name;
-  }
-
-  @NonNull
-  public String color() {
-    return color;
-  }
-
-  @NonNull
-  public String size() {
-    return size;
-  }
-
-  @Override
-  public String getOpeningDelimiter() {
-    return DELIMITER_STRING;
-  }
-
-  @Override
-  public String getClosingDelimiter() {
-    return DELIMITER_STRING;
-  }
-
-  @Override
-  @NonNull
-  public String toString() {
-    return "IconNode{" +
-      "name='" + name + '\'' +
-      ", color='" + color + '\'' +
-      ", size='" + size + '\'' +
-      '}';
-  }
-}
-
-class IconGroupNode extends CustomNode {
-
-}
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/DelimiterProcessorSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/DelimiterProcessorSample.java
deleted file mode 100644
index 9cb90984..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/DelimiterProcessorSample.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package io.noties.markwon.app.samples;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.node.Emphasis;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-import org.commonmark.parser.Parser;
-import org.commonmark.parser.delimiter.DelimiterProcessor;
-import org.commonmark.parser.delimiter.DelimiterRun;
-
-import io.noties.markwon.AbstractMarkwonPlugin;
-import io.noties.markwon.Markwon;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200630194017",
-  title = "Custom delimiter processor",
-  description = "Custom parsing delimiter processor with `?` character",
-  artifacts = MarkwonArtifact.CORE,
-  tags = Tag.parsing
-)
-public class DelimiterProcessorSample extends MarkwonTextViewSample {
-  @Override
-  public void render() {
-    final String md = "" +
-      "?hello? there!";
-
-    final Markwon markwon = Markwon.builder(context)
-      .usePlugin(new AbstractMarkwonPlugin() {
-        @Override
-        public void configureParser(@NonNull Parser.Builder builder) {
-          builder.customDelimiterProcessor(new QuestionDelimiterProcessor());
-        }
-      })
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
-
-class QuestionDelimiterProcessor implements DelimiterProcessor {
-
-  @Override
-  public char getOpeningCharacter() {
-    return '?';
-  }
-
-  @Override
-  public char getClosingCharacter() {
-    return '?';
-  }
-
-  @Override
-  public int getMinLength() {
-    return 1;
-  }
-
-  @Override
-  public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) {
-    if (opener.length() >= 1 && closer.length() >= 1) {
-      return 1;
-    }
-    return 0;
-  }
-
-  @Override
-  public void process(Text opener, Text closer, int delimiterUse) {
-    final Node node = new Emphasis();
-
-    Node tmp = opener.getNext();
-    while (tmp != null && tmp != closer) {
-      Node next = tmp.getNext();
-      node.appendChild(tmp);
-      tmp = next;
-    }
-
-    opener.insertAfter(node);
-  }
-}
\ No newline at end of file
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/DisableNodeSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/DisableNodeSample.java
index 398f9f78..8bfd7d17 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/DisableNodeSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/DisableNodeSample.java
@@ -2,7 +2,7 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Heading;
+import com.vladsch.flexmark.ast.Heading;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/EnabledBlockTypesSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/EnabledBlockTypesSample.kt
deleted file mode 100644
index 9a0e7bcc..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/EnabledBlockTypesSample.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package io.noties.markwon.app.samples
-
-import io.noties.markwon.AbstractMarkwonPlugin
-import io.noties.markwon.Markwon
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
-import io.noties.markwon.core.CorePlugin
-import io.noties.markwon.sample.annotations.MarkwonArtifact
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo
-import io.noties.markwon.sample.annotations.Tag
-import org.commonmark.node.BlockQuote
-import org.commonmark.parser.Parser
-
-@MarkwonSampleInfo(
-  id = "20200627075012",
-  title = "Enabled markdown blocks",
-  description = "Modify/inspect enabled by `CorePlugin` block types. " +
-    "Disable quotes or other blocks from being parsed",
-  artifacts = [MarkwonArtifact.CORE],
-  tags = [Tag.parsing, Tag.block, Tag.plugin]
-)
-class EnabledBlockTypesSample : MarkwonTextViewSample() {
-  override fun render() {
-    val md = """
-      # Heading
-      ## Second level
-      > Quote is not handled
-    """.trimIndent()
-
-    val markwon = Markwon.builder(context)
-      .usePlugin(object : AbstractMarkwonPlugin() {
-        override fun configureParser(builder: Parser.Builder) {
-          // obtain all enabled block types
-          val enabledBlockTypes = CorePlugin.enabledBlockTypes()
-          // it is safe to modify returned collection
-          // remove quotes
-          enabledBlockTypes.remove(BlockQuote::class.java)
-
-          builder.enabledBlockTypes(enabledBlockTypes)
-        }
-      })
-      .build()
-
-    markwon.setMarkdown(textView, md)
-  }
-}
\ No newline at end of file
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/ExcludeFromParsingSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/ExcludeFromParsingSample.kt
index 95c34f62..dd3b44ae 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/ExcludeFromParsingSample.kt
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/ExcludeFromParsingSample.kt
@@ -16,7 +16,7 @@ import java.util.regex.Pattern
   artifacts = [MarkwonArtifact.CORE],
   tags = [Tag.parsing]
 )
-class ExcludeFromParsingSample : MarkwonTextViewSample() {
+public class ExcludeFromParsingSample : MarkwonTextViewSample() {
   override fun render() {
 
     // cannot have continuous markdown between parts (so a node started in one part and ended in other)
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java
deleted file mode 100644
index 884d4c5c..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package io.noties.markwon.app.samples;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.node.Link;
-import org.commonmark.node.Node;
-import org.commonmark.parser.InlineParserFactory;
-import org.commonmark.parser.Parser;
-
-import java.util.regex.Pattern;
-
-import io.noties.markwon.AbstractMarkwonPlugin;
-import io.noties.markwon.Markwon;
-import io.noties.markwon.app.BuildConfig;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.inlineparser.InlineProcessor;
-import io.noties.markwon.inlineparser.MarkwonInlineParser;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200629162023",
-  title = "User mention and issue (via text)",
-  description = "Github-like user mention and issue " +
-    "rendering via `CorePlugin.OnTextAddedListener`",
-  artifacts = {MarkwonArtifact.CORE, MarkwonArtifact.INLINE_PARSER},
-  tags = {Tag.parsing, Tag.textAddedListener, Tag.rendering}
-)
-public class GithubUserIssueInlineParsingSample extends MarkwonTextViewSample {
-  @Override
-  public void render() {
-    final String md = "" +
-      "# Custom Extension 2\n" +
-      "\n" +
-      "This is an issue #1\n" +
-      "Done by @noties and other @dude";
-
-    final InlineParserFactory inlineParserFactory = MarkwonInlineParser.factoryBuilder()
-      // include all current defaults (otherwise will be empty - contain only our inline-processors)
-      //  included by default, to create factory-builder without defaults call `factoryBuilderNoDefaults`
-//                .includeDefaults()
-      .addInlineProcessor(new IssueInlineProcessor())
-      .addInlineProcessor(new UserInlineProcessor())
-      .build();
-
-    final Markwon markwon = Markwon.builder(context)
-      .usePlugin(new AbstractMarkwonPlugin() {
-        @Override
-        public void configureParser(@NonNull Parser.Builder builder) {
-          builder.inlineParserFactory(inlineParserFactory);
-        }
-      })
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
-
-class IssueInlineProcessor extends InlineProcessor {
-
-  private static final Pattern RE = Pattern.compile("\\d+");
-
-  @Override
-  public char specialCharacter() {
-    return '#';
-  }
-
-  @Override
-  protected Node parse() {
-    final String id = match(RE);
-    if (id != null) {
-      final Link link = new Link(createIssueOrPullRequestLinkDestination(id), null);
-      link.appendChild(text("#" + id));
-      return link;
-    }
-    return null;
-  }
-
-  @NonNull
-  private static String createIssueOrPullRequestLinkDestination(@NonNull String id) {
-    return BuildConfig.GIT_REPOSITORY + "/issues/" + id;
-  }
-}
-
-class UserInlineProcessor extends InlineProcessor {
-
-  private static final Pattern RE = Pattern.compile("\\w+");
-
-  @Override
-  public char specialCharacter() {
-    return '@';
-  }
-
-  @Override
-  protected Node parse() {
-    final String user = match(RE);
-    if (user != null) {
-      final Link link = new Link(createUserLinkDestination(user), null);
-      link.appendChild(text("@" + user));
-      return link;
-    }
-    return null;
-  }
-
-  @NonNull
-  private static String createUserLinkDestination(@NonNull String user) {
-    return "https://github.com/" + user;
-  }
-}
\ No newline at end of file
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java
index 68f1e9c2..c9225018 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java
@@ -2,7 +2,7 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Link;
+import com.vladsch.flexmark.ast.Link;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingColorSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingColorSample.java
index a7ed4c57..4b6b16a0 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingColorSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingColorSample.java
@@ -5,7 +5,7 @@ import android.text.style.ForegroundColorSpan;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Heading;
+import com.vladsch.flexmark.ast.Heading;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceBlockHandlerSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceBlockHandlerSample.java
index ae0f1083..733f41f0 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceBlockHandlerSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceBlockHandlerSample.java
@@ -2,8 +2,8 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Heading;
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.BlockHandlerDef;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceSample.java
index be3e3f54..99fb5853 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/HeadingNoSpaceSample.java
@@ -2,7 +2,7 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Heading;
+import com.vladsch.flexmark.ast.Heading;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/InlinePluginNoDefaultsSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/InlinePluginNoDefaultsSample.java
deleted file mode 100644
index 1184acb2..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/InlinePluginNoDefaultsSample.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.noties.markwon.app.samples;
-
-import io.noties.markwon.Markwon;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.inlineparser.MarkwonInlineParser;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200629170857",
-  title = "Inline parsing without defaults",
-  description = "Configure inline parser plugin to **not** have any **inline** parsing",
-  artifacts = {MarkwonArtifact.INLINE_PARSER},
-  tags = {Tag.parsing}
-)
-public class InlinePluginNoDefaultsSample extends MarkwonTextViewSample {
-  @Override
-  public void render() {
-    final String md = "" +
-      "# Heading\n" +
-      "`code` inlined and **bold** here";
-
-    final Markwon markwon = Markwon.builder(context)
-      .usePlugin(MarkwonInlineParserPlugin.create(MarkwonInlineParser.factoryBuilderNoDefaults()))
-//                .usePlugin(MarkwonInlineParserPlugin.create(MarkwonInlineParser.factoryBuilderNoDefaults(), factoryBuilder -> {
-//                    // if anything, they can be included here
-////                    factoryBuilder.includeDefaults()
-//                }))
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/LetterOrderedListSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/LetterOrderedListSample.java
index f8b99f88..be38c0ed 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/LetterOrderedListSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/LetterOrderedListSample.java
@@ -5,10 +5,10 @@ import android.util.SparseIntArray;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.BulletList;
-import org.commonmark.node.ListItem;
-import org.commonmark.node.Node;
-import org.commonmark.node.OrderedList;
+import com.vladsch.flexmark.ast.BulletList;
+import com.vladsch.flexmark.ast.ListItem;
+import com.vladsch.flexmark.ast.OrderedList;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/LinkRemoveUnderlineSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/LinkRemoveUnderlineSample.java
index a39a833d..da805644 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/LinkRemoveUnderlineSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/LinkRemoveUnderlineSample.java
@@ -6,7 +6,7 @@ import android.text.style.UpdateAppearance;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Link;
+import com.vladsch.flexmark.ast.Link;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/LinkTitleSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/LinkTitleSample.java
index 0bc93e6e..6edba2a0 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/LinkTitleSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/LinkTitleSample.java
@@ -8,7 +8,7 @@ import android.widget.Toast;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Link;
+import com.vladsch.flexmark.ast.Link;
 
 import java.util.Locale;
 
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/NoParsingSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/NoParsingSample.java
deleted file mode 100644
index 55ed7fe9..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/NoParsingSample.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package io.noties.markwon.app.samples;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.parser.Parser;
-
-import java.util.Collections;
-
-import io.noties.markwon.AbstractMarkwonPlugin;
-import io.noties.markwon.Markwon;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.inlineparser.MarkwonInlineParser;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200629171212",
-  title = "No parsing",
-  description = "All commonmark parsing is disabled (both inlines and blocks)",
-  artifacts = MarkwonArtifact.CORE,
-  tags = {Tag.parsing, Tag.rendering}
-)
-public class NoParsingSample extends MarkwonTextViewSample {
-  @Override
-  public void render() {
-    final String md = "" +
-      "# Heading\n" +
-      "[link](#) was _here_ and `then` and it was:\n" +
-      "> a quote\n" +
-      "```java\n" +
-      "final int someJavaCode = 0;\n" +
-      "```\n";
-
-    final Markwon markwon = Markwon.builder(context)
-      // disable inline parsing
-      .usePlugin(MarkwonInlineParserPlugin.create(MarkwonInlineParser.factoryBuilderNoDefaults()))
-      .usePlugin(new AbstractMarkwonPlugin() {
-        @Override
-        public void configureParser(@NonNull Parser.Builder builder) {
-          builder.enabledBlockTypes(Collections.emptySet());
-        }
-      })
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/ParagraphSpanStyle.java b/app-sample/src/main/java/io/noties/markwon/app/samples/ParagraphSpanStyle.java
index 9174584e..8daa2075 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/ParagraphSpanStyle.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/ParagraphSpanStyle.java
@@ -5,7 +5,7 @@ import android.text.style.ForegroundColorSpan;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Paragraph;
+import com.vladsch.flexmark.ast.Paragraph;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/RecyclerSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/RecyclerSample.java
index 599e1a18..0093e1ed 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/RecyclerSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/RecyclerSample.java
@@ -3,8 +3,8 @@ package io.noties.markwon.app.samples;
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.LinearLayoutManager;
 
-import org.commonmark.ext.gfm.tables.TableBlock;
-import org.commonmark.node.FencedCodeBlock;
+import com.vladsch.flexmark.ast.FencedCodeBlock;
+import com.vladsch.flexmark.ext.tables.TableBlock;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
@@ -59,7 +59,7 @@ public class RecyclerSample extends MarkwonRecyclerViewSample {
             // NB the `trim` operation on literal (as code will have a new line at the end)
             final CharSequence code = visitor.configuration()
               .syntaxHighlight()
-              .highlight(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral().trim());
+              .highlight(fencedCodeBlock.getInfo().unescape(), fencedCodeBlock.toAstString(false).trim());
             visitor.builder().append(code);
           });
         }
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/ThematicBreakBottomMarginSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/ThematicBreakBottomMarginSample.java
index 5f0edaf6..5725d279 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/ThematicBreakBottomMarginSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/ThematicBreakBottomMarginSample.java
@@ -2,8 +2,8 @@ package io.noties.markwon.app.samples;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
-import org.commonmark.node.ThematicBreak;
+import com.vladsch.flexmark.ast.ThematicBreak;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.BlockHandlerDef;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/ToastDynamicContentSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/ToastDynamicContentSample.kt
index 7fadb663..f05d9676 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/ToastDynamicContentSample.kt
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/ToastDynamicContentSample.kt
@@ -19,7 +19,7 @@ import io.noties.markwon.sample.annotations.Tag
   artifacts = [MarkwonArtifact.CORE, MarkwonArtifact.IMAGE],
   tags = [Tag.toast, Tag.hack]
 )
-class ToastDynamicContentSample : MarkwonTextViewSample() {
+public class ToastDynamicContentSample : MarkwonTextViewSample() {
   override fun render() {
     val md = """
       # Head!
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/basics/SimpleWalkthrough.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/basics/SimpleWalkthrough.kt
index 26c99c2f..ba397565 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/basics/SimpleWalkthrough.kt
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/basics/SimpleWalkthrough.kt
@@ -1,13 +1,13 @@
 package io.noties.markwon.app.samples.basics
 
 import android.text.Spanned
+import com.vladsch.flexmark.util.ast.Node
 import io.noties.markwon.Markwon
 import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
 import io.noties.markwon.core.CorePlugin
 import io.noties.markwon.sample.annotations.MarkwonArtifact
 import io.noties.markwon.sample.annotations.MarkwonSampleInfo
 import io.noties.markwon.sample.annotations.Tag
-import org.commonmark.node.Node
 
 @MarkwonSampleInfo(
   id = "20200626153426",
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingTooltipSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingTooltipSample.java
index ac2d962e..cc933abe 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingTooltipSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingTooltipSample.java
@@ -15,8 +15,9 @@ import android.widget.Toast;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.CustomNode;
-import org.commonmark.node.Node;
+
+import com.vladsch.flexmark.parser.InlineParser;
+import com.vladsch.flexmark.parser.internal.InlineParserImpl;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -26,8 +27,6 @@ import io.noties.markwon.Markwon;
 import io.noties.markwon.MarkwonVisitor;
 import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
 import io.noties.markwon.image.ImagesPlugin;
-import io.noties.markwon.inlineparser.InlineProcessor;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
 import io.noties.markwon.sample.annotations.MarkwonArtifact;
 import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
 import io.noties.markwon.sample.annotations.Tag;
@@ -79,7 +78,7 @@ public class InlineParsingTooltipSample extends MarkwonTextViewSample {
   }
 }
 
-class TooltipInlineProcessor extends InlineProcessor {
+class TooltipInlineProcessor extends InlineParserImpl {
 
   // NB! without bang
   // `\\{` is required (although marked as redundant), without it - runtime crash
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexLegacySample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexLegacySample.java
deleted file mode 100644
index bedd3982..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexLegacySample.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package io.noties.markwon.app.samples.latex;
-
-import io.noties.markwon.Markwon;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.app.samples.latex.shared.LatexHolder;
-import io.noties.markwon.ext.latex.JLatexMathPlugin;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200701090335",
-  title = "LaTeX blocks in legacy mode",
-  description = "Sample using _legacy_ LaTeX block parsing (pre `4.3.0` Markwon version)",
-  artifacts = MarkwonArtifact.EXT_LATEX,
-  tags = Tag.rendering
-)
-public class LatexLegacySample extends MarkwonTextViewSample {
-  @Override
-  public void render() {
-    final String md = "" +
-      "# LaTeX legacy\n" +
-      "There are no inlines in previous versions, only blocks:\n" +
-      "$$\n" +
-      "" + LatexHolder.LATEX_BOXES + "\n" +
-      "$$\n" +
-      "yeah";
-
-    final Markwon markwon = Markwon.builder(context)
-      .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
-        builder.blocksLegacy(true);
-      }))
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexOmegaSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexOmegaSample.java
index d017018a..814a44e6 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexOmegaSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexOmegaSample.java
@@ -3,7 +3,6 @@ package io.noties.markwon.app.samples.latex;
 import io.noties.markwon.Markwon;
 import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
 import io.noties.markwon.ext.latex.JLatexMathPlugin;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
 import io.noties.markwon.sample.annotations.MarkwonArtifact;
 import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
 import io.noties.markwon.sample.annotations.Tag;
@@ -27,7 +26,6 @@ public class LatexOmegaSample extends MarkwonTextViewSample {
       "$$\\Omega$$";
 
     final Markwon markwon = Markwon.builder(context)
-      .usePlugin(MarkwonInlineParserPlugin.create())
       .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
         builder.inlinesEnabled(true);
       }))
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexThemeSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexThemeSample.java
index b3b26679..722c02ff 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexThemeSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/latex/LatexThemeSample.java
@@ -8,7 +8,6 @@ import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
 import io.noties.markwon.app.samples.latex.shared.LatexHolder;
 import io.noties.markwon.ext.latex.JLatexMathPlugin;
 import io.noties.markwon.ext.latex.JLatexMathTheme;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
 import io.noties.markwon.sample.annotations.MarkwonArtifact;
 import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
 import io.noties.markwon.sample.annotations.Tag;
@@ -35,7 +34,6 @@ public class LatexThemeSample extends MarkwonTextViewSample {
     final int blockPadding = (int) (16 * context.getResources().getDisplayMetrics().density + 0.5F);
 
     final Markwon markwon = Markwon.builder(context)
-      .usePlugin(MarkwonInlineParserPlugin.create())
       .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
         builder.inlinesEnabled(true);
         builder.theme()
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/notification/RemoteViewsSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/notification/RemoteViewsSample.java
index 2d11f19d..73760dae 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/notification/RemoteViewsSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/notification/RemoteViewsSample.java
@@ -13,13 +13,13 @@ import android.widget.RemoteViews;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.ext.gfm.strikethrough.Strikethrough;
-import org.commonmark.node.BlockQuote;
-import org.commonmark.node.Code;
-import org.commonmark.node.Emphasis;
-import org.commonmark.node.Heading;
-import org.commonmark.node.ListItem;
-import org.commonmark.node.StrongEmphasis;
+import com.vladsch.flexmark.ast.BlockQuote;
+import com.vladsch.flexmark.ast.Code;
+import com.vladsch.flexmark.ast.Emphasis;
+import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.ListItem;
+import com.vladsch.flexmark.ast.StrongEmphasis;
+import com.vladsch.flexmark.ext.gfm.strikethrough.Strikethrough;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.Markwon;
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/parser/CustomHeadingParserSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/parser/CustomHeadingParserSample.kt
deleted file mode 100644
index f539733d..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/parser/CustomHeadingParserSample.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package io.noties.markwon.app.samples.parser
-
-import io.noties.markwon.AbstractMarkwonPlugin
-import io.noties.markwon.Markwon
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
-import io.noties.markwon.core.CorePlugin
-import io.noties.markwon.sample.annotations.MarkwonArtifact
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo
-import io.noties.markwon.sample.annotations.Tag
-import org.commonmark.node.Heading
-import org.commonmark.parser.Parser
-import org.commonmark.parser.block.BlockParserFactory
-import org.commonmark.parser.block.BlockStart
-import org.commonmark.parser.block.MatchedBlockParser
-import org.commonmark.parser.block.ParserState
-
-@MarkwonSampleInfo(
-  id = "20201111221207",
-  title = "Custom heading parser",
-  description = "Custom heading block parser. Actual parser is not implemented",
-  artifacts = [MarkwonArtifact.CORE],
-  tags = [Tag.parsing, Tag.heading]
-)
-class CustomHeadingParserSample : MarkwonTextViewSample() {
-  override fun render() {
-    val md = "#Head"
-    val markwon = Markwon.builder(context)
-      .usePlugin(object : AbstractMarkwonPlugin() {
-        override fun configureParser(builder: Parser.Builder) {
-          val enabled = CorePlugin.enabledBlockTypes()
-            .filter { it != Heading::class.java }
-            .toSet()
-          builder.enabledBlockTypes(enabled)
-          builder.customBlockParserFactory(MyHeadingBlockParserFactory)
-        }
-      })
-      .build()
-    markwon.setMarkdown(textView, md)
-  }
-
-  object MyHeadingBlockParserFactory : BlockParserFactory {
-    override fun tryStart(state: ParserState, matchedBlockParser: MatchedBlockParser): BlockStart? {
-      // TODO("Not yet implemented")
-      return null
-    }
-  }
-}
\ No newline at end of file
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/plugins/TableOfContentsSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/plugins/TableOfContentsSample.java
deleted file mode 100644
index fe11bfd9..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/plugins/TableOfContentsSample.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package io.noties.markwon.app.samples.plugins;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.node.AbstractVisitor;
-import org.commonmark.node.BulletList;
-import org.commonmark.node.CustomBlock;
-import org.commonmark.node.Heading;
-import org.commonmark.node.Link;
-import org.commonmark.node.ListItem;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-import io.noties.markwon.AbstractMarkwonPlugin;
-import io.noties.markwon.Markwon;
-import io.noties.markwon.MarkwonVisitor;
-import io.noties.markwon.app.R;
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.app.samples.plugins.shared.AnchorHeadingPlugin;
-import io.noties.markwon.core.SimpleBlockNodeVisitor;
-import io.noties.markwon.sample.annotations.MarkwonArtifact;
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
-import io.noties.markwon.sample.annotations.Tag;
-
-@MarkwonSampleInfo(
-  id = "20200629161226",
-  title = "Table of contents",
-  description = "Sample plugin that adds a table of contents header",
-  artifacts = MarkwonArtifact.CORE,
-  tags = {Tag.rendering, Tag.plugin}
-)
-public class TableOfContentsSample extends MarkwonTextViewSample {
-
-  @Override
-  public void render() {
-    final String lorem = context.getString(R.string.lorem);
-    final String md = "" +
-      "# First\n" +
-      "" + lorem + "\n\n" +
-      "# Second\n" +
-      "" + lorem + "\n\n" +
-      "## Second level\n\n" +
-      "" + lorem + "\n\n" +
-      "### Level 3\n\n" +
-      "" + lorem + "\n\n" +
-      "# First again\n" +
-      "" + lorem + "\n\n";
-
-    final Markwon markwon = Markwon.builder(context)
-      .usePlugin(new TableOfContentsPlugin())
-      // NB! plugin is defined in `AnchorSample` file
-      .usePlugin(new AnchorHeadingPlugin((view, top) -> scrollView.smoothScrollTo(0, top)))
-      .build();
-
-    markwon.setMarkdown(textView, md);
-  }
-}
-
-class TableOfContentsPlugin extends AbstractMarkwonPlugin {
-  @Override
-  public void configure(@NonNull Registry registry) {
-    // just to make it explicit
-    registry.require(AnchorHeadingPlugin.class);
-  }
-
-  @Override
-  public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
-    builder.on(TableOfContentsBlock.class, new SimpleBlockNodeVisitor());
-  }
-
-  @Override
-  public void beforeRender(@NonNull Node node) {
-
-    // custom block to hold TOC
-    final TableOfContentsBlock block = new TableOfContentsBlock();
-
-    // create TOC title
-    {
-      final Text text = new Text("Table of contents");
-      final Heading heading = new Heading();
-      // important one - set TOC heading level
-      heading.setLevel(1);
-      heading.appendChild(text);
-      block.appendChild(heading);
-    }
-
-    final HeadingVisitor visitor = new HeadingVisitor(block);
-    node.accept(visitor);
-
-    // make it the very first node in rendered markdown
-    node.prependChild(block);
-  }
-
-  private static class HeadingVisitor extends AbstractVisitor {
-
-    private final BulletList bulletList = new BulletList();
-    private final StringBuilder builder = new StringBuilder();
-    private boolean isInsideHeading;
-
-    HeadingVisitor(@NonNull Node node) {
-      node.appendChild(bulletList);
-    }
-
-    @Override
-    public void visit(Heading heading) {
-      this.isInsideHeading = true;
-      try {
-        // reset build from previous content
-        builder.setLength(0);
-
-        // obtain level (can additionally filter by level, to skip lower ones)
-        final int level = heading.getLevel();
-
-        // build heading title
-        visitChildren(heading);
-
-        // initial list item
-        final ListItem listItem = new ListItem();
-
-        Node parent = listItem;
-        Node node = listItem;
-
-        for (int i = 1; i < level; i++) {
-          final ListItem li = new ListItem();
-          final BulletList bulletList = new BulletList();
-          bulletList.appendChild(li);
-          parent.appendChild(bulletList);
-          parent = li;
-          node = li;
-        }
-
-        final String content = builder.toString();
-        final Link link = new Link("#" + AnchorHeadingPlugin.createAnchor(content), null);
-        final Text text = new Text(content);
-        link.appendChild(text);
-        node.appendChild(link);
-        bulletList.appendChild(listItem);
-
-
-      } finally {
-        isInsideHeading = false;
-      }
-    }
-
-    @Override
-    public void visit(Text text) {
-      // can additionally check if we are building heading (to skip all other texts)
-      if (isInsideHeading) {
-        builder.append(text.getLiteral());
-      }
-    }
-  }
-
-  private static class TableOfContentsBlock extends CustomBlock {
-  }
-}
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/table/TableLatexSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/table/TableLatexSample.java
index 26f4f654..1a0dbc92 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/table/TableLatexSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/table/TableLatexSample.java
@@ -5,7 +5,6 @@ import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
 import io.noties.markwon.ext.latex.JLatexMathPlugin;
 import io.noties.markwon.ext.tables.TablePlugin;
 import io.noties.markwon.image.ImagesPlugin;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
 import io.noties.markwon.sample.annotations.MarkwonArtifact;
 import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
 import io.noties.markwon.sample.annotations.Tag;
@@ -34,7 +33,6 @@ public class TableLatexSample extends MarkwonTextViewSample {
       "\n";
 
     final Markwon markwon = Markwon.builder(context)
-      .usePlugin(MarkwonInlineParserPlugin.create())
       .usePlugin(ImagesPlugin.create())
       .usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> builder.inlinesEnabled(true)))
       .usePlugin(TablePlugin.create(context))
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateNestedSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateNestedSample.kt
deleted file mode 100644
index cf275342..00000000
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateNestedSample.kt
+++ /dev/null
@@ -1,157 +0,0 @@
-package io.noties.markwon.app.samples.tasklist
-
-import android.text.style.ClickableSpan
-import android.view.View
-import io.noties.debug.Debug
-import io.noties.markwon.AbstractMarkwonPlugin
-import io.noties.markwon.Markwon
-import io.noties.markwon.MarkwonVisitor
-import io.noties.markwon.SoftBreakAddsNewLinePlugin
-import io.noties.markwon.SpannableBuilder
-import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
-import io.noties.markwon.ext.tasklist.TaskListItem
-import io.noties.markwon.ext.tasklist.TaskListPlugin
-import io.noties.markwon.ext.tasklist.TaskListProps
-import io.noties.markwon.ext.tasklist.TaskListSpan
-import io.noties.markwon.sample.annotations.MarkwonArtifact
-import io.noties.markwon.sample.annotations.MarkwonSampleInfo
-import io.noties.markwon.sample.annotations.Tag
-import org.commonmark.node.AbstractVisitor
-import org.commonmark.node.Block
-import org.commonmark.node.HardLineBreak
-import org.commonmark.node.Node
-import org.commonmark.node.Paragraph
-import org.commonmark.node.SoftLineBreak
-import org.commonmark.node.Text
-
-@MarkwonSampleInfo(
-  id = "20201228120444",
-  title = "Task list mutate nested",
-  description = "Task list mutation with nested items",
-  artifacts = [MarkwonArtifact.EXT_TASKLIST],
-  tags = [Tag.plugin]
-)
-class TaskListMutateNestedSample : MarkwonTextViewSample() {
-  override fun render() {
-    val md = """
-      # Task list
-      - [ ] not done
-      - [X] done
-        - [ ] nested not done 
-          and text and textand text and text
-        - [X] nested done
-    """.trimIndent()
-
-    val markwon = Markwon.builder(context)
-      .usePlugin(TaskListPlugin.create(context))
-      .usePlugin(SoftBreakAddsNewLinePlugin.create())
-      .usePlugin(object : AbstractMarkwonPlugin() {
-        override fun configureVisitor(builder: MarkwonVisitor.Builder) {
-          builder.on(TaskListItem::class.java) { visitor, node ->
-
-            val length = visitor.length()
-
-            visitor.visitChildren(node)
-
-            TaskListProps.DONE.set(visitor.renderProps(), node.isDone)
-
-            val spans = visitor.configuration()
-              .spansFactory()
-              .get(TaskListItem::class.java)
-              ?.getSpans(visitor.configuration(), visitor.renderProps())
-
-            if (spans != null) {
-
-              val taskListSpan = if (spans is Array<*>) {
-                spans.first { it is TaskListSpan } as? TaskListSpan
-              } else {
-                spans as? TaskListSpan
-              }
-
-              Debug.i("#### ${visitor.builder().substring(length, length + 3)}")
-              val content = TaskListContextVisitor.contentLength(node)
-              Debug.i("#### content: $content, '${visitor.builder().subSequence(length, length + content)}'")
-
-              if (content > 0 && taskListSpan != null) {
-                // maybe additionally identify this task list (for persistence)
-                visitor.builder().setSpan(
-                  ToggleTaskListSpan(taskListSpan, visitor.builder().substring(length, length + content)),
-                  length,
-                  length + content
-                )
-              }
-            }
-
-            SpannableBuilder.setSpans(
-              visitor.builder(),
-              spans,
-              length,
-              visitor.length()
-            )
-
-            if (visitor.hasNext(node)) {
-              visitor.ensureNewLine()
-            }
-          }
-        }
-      })
-      .build()
-
-    markwon.setMarkdown(textView, md)
-  }
-
-  class TaskListContextVisitor : AbstractVisitor() {
-
-    companion object {
-      fun contentLength(node: Node): Int {
-        val visitor = TaskListContextVisitor()
-        visitor.visitChildren(node)
-        return visitor.contentLength
-      }
-    }
-
-    var contentLength: Int = 0
-
-    override fun visit(text: Text) {
-      super.visit(text)
-      contentLength += text.literal.length
-    }
-
-    // NB! if count both soft and hard breaks as having length of 1
-    override fun visit(softLineBreak: SoftLineBreak?) {
-      super.visit(softLineBreak)
-      contentLength += 1
-    }
-
-    // NB! if count both soft and hard breaks as having length of 1
-    override fun visit(hardLineBreak: HardLineBreak?) {
-      super.visit(hardLineBreak)
-      contentLength += 1
-    }
-
-    override fun visitChildren(parent: Node) {
-      var node = parent.firstChild
-      while (node != null) {
-        // A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
-        // node after visiting it. So get the next node before visiting.
-        val next = node.next
-        if (node is Block && node !is Paragraph) {
-          break
-        }
-        node.accept(this)
-        node = next
-      }
-    }
-  }
-
-  class ToggleTaskListSpan(
-    val span: TaskListSpan,
-    val content: String
-  ) : ClickableSpan() {
-    override fun onClick(widget: View) {
-      span.isDone = !span.isDone
-      widget.invalidate()
-      Debug.i("task-list click, isDone: ${span.isDone}, content: '$content'")
-    }
-  }
-}
\ No newline at end of file
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateSample.java
index bc907c37..abdb1622 100644
--- a/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateSample.java
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/tasklist/TaskListMutateSample.java
@@ -14,7 +14,6 @@ import io.noties.markwon.Markwon;
 import io.noties.markwon.MarkwonSpansFactory;
 import io.noties.markwon.SpanFactory;
 import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
-import io.noties.markwon.ext.tasklist.TaskListItem;
 import io.noties.markwon.ext.tasklist.TaskListPlugin;
 import io.noties.markwon.ext.tasklist.TaskListSpan;
 import io.noties.markwon.sample.annotations.MarkwonArtifact;
@@ -23,6 +22,8 @@ import io.noties.markwon.sample.annotations.Tag;
 
 import static io.noties.markwon.app.samples.tasklist.shared.TaskListHolder.MD;
 
+import com.vladsch.flexmark.ext.gfm.tasklist.TaskListItem;
+
 @MarkwonSampleInfo(
   id = "20200702140901",
   title = "GFM task list mutate",
diff --git a/build.gradle b/build.gradle
index 8d24619f..0b7b868e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,13 +1,14 @@
 buildscript {
-    ext.kotlin_version = '1.4.10'
+    ext.kotlin_version = '1.7.20'
     repositories {
         google()
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.0.2'
+        classpath 'com.android.tools.build:gradle:7.4.0'
         classpath 'com.github.ben-manes:gradle-versions-plugin:0.28.0'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
     }
 }
 
@@ -27,16 +28,23 @@ allprojects {
     tasks.withType(Javadoc) {
         enabled = false
     }
+
+    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
+        kotlinOptions {
+            // Treat all Kotlin warnings as errors
+            // allWarningsAsErrors = true
+
+            freeCompilerArgs += '-opt-in=kotlin.RequiresOptIn'
+            // Set JVM target to 11
+            jvmTarget = JavaVersion.VERSION_11
+        }
+    }
 }
 
 task clean(type: Delete) {
     delete rootProject.buildDir
 }
 
-wrapper {
-    gradleVersion '6.1.1'
-    distributionType 'all'
-}
 
 if (hasProperty('local')) {
     if (!hasProperty('LOCAL_MAVEN_URL')) {
@@ -49,10 +57,10 @@ if (hasProperty('local')) {
 ext {
 
     config = [
-            'build-tools'    : '29.0.3',
-            'compile-sdk'    : 29,
-            'target-sdk'     : 29,
-            'min-sdk'        : 16,
+            'build-tools'    : '33.0.1',
+            'compile-sdk'    : 33,
+            'target-sdk'     : 33,
+            'min-sdk'        : 21,
             'push-aar-gradle': 'https://raw.githubusercontent.com/noties/gradle-mvn-push/master/gradle-mvn-push-aar.gradle'
     ]
 
@@ -72,6 +80,7 @@ ext {
             'x-appcompat'             : 'androidx.appcompat:appcompat:1.1.0',
             'x-cardview'              : 'androidx.cardview:cardview:1.0.0',
             'x-fragment'              : 'androidx.fragment:fragment:1.0.0',
+            'flexmark'                : 'com.vladsch.flexmark:flexmark-all:0.64.0',
             'commonmark'              : "com.atlassian.commonmark:commonmark:$commonMarkVersion",
             'commonmark-strikethrough': "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:$commonMarkVersion",
             'commonmark-table'        : "com.atlassian.commonmark:commonmark-ext-gfm-tables:$commonMarkVersion",
diff --git a/gradle.properties b/gradle.properties
index f7ef5b5d..35d2bac2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,19 +5,21 @@ org.gradle.configureondemand=true
 
 android.useAndroidX=true
 android.enableJetifier=true
-android.enableBuildCache=true
-android.buildCacheDir=build/pre-dex-cache
 
-VERSION_NAME=4.6.2
+VERSION_NAME=5.0.0
 
 GROUP=io.noties.markwon
 POM_DESCRIPTION=Markwon markdown for Android
-POM_URL=https://github.com/noties/Markwon
-POM_SCM_URL=https://github.com/noties/Markwon
-POM_SCM_CONNECTION=scm:git:git://github.com/noties/Markwon.git
-POM_SCM_DEV_CONNECTION=scm:git:git://github.com/noties/Markwon.git
+POM_URL=https://github.com/cpacm/Markwon
+POM_SCM_URL=https://github.com/cpacm/Markwon
+POM_SCM_CONNECTION=scm:git:git://github.com/cpacm/Markwon.git
+POM_SCM_DEV_CONNECTION=scm:git:git://github.com/cpacm/Markwon.git
 POM_LICENCE_NAME=The Apache Software License, Version 2.0
 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
 POM_LICENCE_DIST=repo
-POM_DEVELOPER_ID=noties
-POM_DEVELOPER_NAME=Dimitry Ivanov
\ No newline at end of file
+POM_DEVELOPER_ID=cpacm
+POM_DEVELOPER_NAME=cpacm
+POM_DEVELOPER_EMAIL=cpacm@8bgm.com
+POM_COMPANY=Github
+POM_OFFICIAL_WEBSITE=https://github.com/cpacm/Markwon
+POM_SCM_ISSUES=https://github.com/cpacm/Markwon/issues
\ No newline at end of file
diff --git a/gradle/publishAllToMavenLocal.sh b/gradle/publishAllToMavenLocal.sh
new file mode 100755
index 00000000..06435186
--- /dev/null
+++ b/gradle/publishAllToMavenLocal.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+./gradlew clean \
+&& ./gradlew :markwon-core:publishToMavenLocal \
+&& ./gradlew :markwon-ext-latex:publishToMavenLocal \
+&& ./gradlew :markwon-ext-strikethrough:publishToMavenLocal \
+&& ./gradlew :markwon-ext-tables:publishToMavenLocal \
+&& ./gradlew :markwon-ext-tasklist:publishToMavenLocal \
+&& ./gradlew :markwon-html:publishToMavenLocal \
+&& ./gradlew :markwon-image:publishToMavenLocal \
+&& ./gradlew :markwon-image-coil:publishToMavenLocal \
+&& ./gradlew :markwon-image-glide:publishToMavenLocal \
+&& ./gradlew :markwon-image-picasso:publishToMavenLocal \
+&& ./gradlew :markwon-linkify:publishToMavenLocal \
+&& ./gradlew :markwon-recycler:publishToMavenLocal \
+&& ./gradlew :markwon-recycler-table:publishToMavenLocal \
+&& ./gradlew :markwon-simple-ext:publishToMavenLocal \
+&& ./gradlew :markwon-syntax-highlight:publishToMavenLocal \
+&& ./gradlew :markwon-editor:publishToMavenLocal \
+&& ./gradlew clean
\ No newline at end of file
diff --git a/gradle/publishMaven.gradle b/gradle/publishMaven.gradle
new file mode 100644
index 00000000..038daa15
--- /dev/null
+++ b/gradle/publishMaven.gradle
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2021 Cpacm
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Based on: https://github.com/mcxiaoke/gradle-mvn-push/blob/master/gradle-mvn-push.gradle.
+ *
+ * To install in a local maven repo:
+ * 1. In the project you want to test, add mavenLocal() to the repositories list.
+ * 2. In Project, run: ./gradlew publishToMavenLocal
+ *
+ * For faster runs add: -x check when building.
+ */
+
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
+version = VERSION_NAME
+group = GROUP
+
+
+
+@SuppressWarnings("GrMethodMayBeStatic")
+def isReleaseBuild() {
+    return !version.contains("SNAPSHOT")
+}
+
+def getReleaseRepositoryUrl() {
+    return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
+            : 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'
+}
+
+def getSnapshotRepositoryUrl() {
+    return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
+            : 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
+}
+
+def getRepositoryUsername() {
+    return hasProperty('USERNAME') ? USERNAME : (hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : '')
+}
+
+def getRepositoryPassword() {
+    return hasProperty('PASSWORD') ? PASSWORD : (hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : '')
+}
+
+def configurePom(pom) {
+    pom.name = POM_NAME
+    pom.packaging = POM_PACKAGING
+    pom.description = POM_DESCRIPTION
+    pom.url = POM_URL
+
+    pom.scm {
+        url = POM_SCM_URL
+        connection = POM_SCM_CONNECTION
+        developerConnection = POM_SCM_DEV_CONNECTION
+    }
+
+    pom.licenses {
+        license {
+            name = POM_LICENCE_NAME
+            url = POM_LICENCE_URL
+            distribution = POM_LICENCE_DIST
+        }
+    }
+
+    pom.issueManagement {
+        system = 'GitHub Issues'
+        url = POM_SCM_ISSUES
+    }
+
+    pom.developers {
+        developer {
+            id = POM_DEVELOPER_ID
+            name = POM_DEVELOPER_NAME
+            email = POM_DEVELOPER_EMAIL
+        }
+    }
+}
+
+afterEvaluate { project ->
+    def isAndroidProject = project.plugins.hasPlugin('com.android.application') || project.plugins.hasPlugin('com.android.library')
+    publishing {
+        repositories {
+            maven {
+                def releasesRepoUrl = getReleaseRepositoryUrl()
+                def snapshotsRepoUrl = getSnapshotRepositoryUrl()
+                url = isReleaseBuild() ? releasesRepoUrl : snapshotsRepoUrl
+                credentials(PasswordCredentials) {
+                    username = getRepositoryUsername()
+                    password = getRepositoryPassword()
+                }
+            }
+        }
+    }
+
+    if (isAndroidProject) {
+        task androidJavadocs(type: Javadoc, dependsOn: assembleDebug) {
+            source = android.sourceSets.main.java.source
+            classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+            // include generated file
+            classpath += project.files("${buildDir}/generated/source/buildConfig/debug")
+            classpath += project.files("${buildDir}/generated/ap_generated_sources/debug/out")
+            excludes = ['**/*.kt']
+        }
+
+        task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
+            classifier = 'javadoc'
+            from androidJavadocs.destinationDir
+        }
+
+        task androidSourcesJar(type: Jar) {
+            classifier = 'sources'
+            from android.sourceSets.main.java.source
+        }
+
+        android.libraryVariants.all { variant ->
+            tasks.androidJavadocs.doFirst {
+                classpath += files(variant.javaCompileProvider.get().classpath.files.join(File.pathSeparator))
+            }
+        }
+    } else {
+
+        task sourcesJar(type: Jar, dependsOn: classes) {
+            classifier = 'sources'
+            from sourceSets.main.allSource
+        }
+
+        task javadocsJar(type: Jar, dependsOn: javadoc) {
+            classifier = 'javadoc'
+            from javadoc.destinationDir
+        }
+
+        artifacts {
+            archives sourcesJar
+            archives javadocsJar
+        }
+    }
+
+    if (JavaVersion.current().isJava8Compatible()) {
+        allprojects {
+            tasks.withType(Javadoc) {
+                options.addStringOption('Xdoclint:none', '-quiet')
+            }
+        }
+    }
+
+    if (JavaVersion.current().isJava9Compatible()) {
+        allprojects {
+            tasks.withType(Javadoc) {
+                options.addBooleanOption('html5', true)
+            }
+        }
+    }
+
+    artifacts {
+        if (isAndroidProject) {
+            archives androidSourcesJar
+            archives androidJavadocsJar
+
+            archives project.tasks.bundleDebugAar
+        }
+    }
+
+    publishing {
+        publications {
+            mavenAgent(MavenPublication) {
+                groupId GROUP
+                artifactId POM_ARTIFACT_ID
+                version version
+                configurePom(pom)
+
+                if (isAndroidProject) {
+                    artifact bundleReleaseAar
+                    artifact androidSourcesJar
+
+                    pom.withXml {
+                        def dependenciesNode = asNode().appendNode('dependencies')
+                        project.configurations.all { configuration ->
+                            def name = configuration.name
+                            // api will duplicate with implementation
+                            if (name == 'releaseImplementation' || name == 'implementation') {
+                                configuration.allDependencies.each {
+                                    if (it.name != "unspecified" && it.version != "unspecified") {
+                                        def groupId = it.group
+                                        def artifactId = it.name
+                                        if (it instanceof ProjectDependency) {
+                                            // skip eg:implementation project(:module)
+                                            // def properties = it.getDependencyProject().getProperties()
+                                            // groupId = properties.get("GROUP")
+                                            // artifactId = properties.get("POM_ARTIFACT_ID")
+                                            // if (!artifactId.equals("annotation")) {return}
+                                            return
+                                        }
+                                        println "dependencies:" + groupId + ":" + artifactId + ":" + it.version
+                                        def dependencyNode = dependenciesNode.appendNode('dependency')
+                                        dependencyNode.appendNode('groupId', groupId)
+                                        dependencyNode.appendNode('artifactId', artifactId)
+                                        dependencyNode.appendNode('version', it.version)
+                                        dependencyNode.appendNode('scope', 'compile')
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    from components.java
+                    artifact sourcesJar
+                    artifact javadocsJar
+                }
+            }
+
+            if (project.plugins.hasPlugin('java-gradle-plugin')) {
+                pluginMaven(MavenPublication) {
+                    groupId GROUP
+                    artifactId POM_ARTIFACT_ID
+                    version version
+                    configurePom(pom)
+                }
+            }
+        }
+    }
+}
+
+signing {
+    required { isReleaseBuild() && gradle.taskGraph.hasTask("publish") }
+    publishing.publications.all { publication ->
+        sign publication
+    }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4e1cc9db..8fad3f5a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/markwon-core/build.gradle b/markwon-core/build.gradle
index e9c088d5..1025d16d 100644
--- a/markwon-core/build.gradle
+++ b/markwon-core/build.gradle
@@ -17,7 +17,7 @@ dependencies {
 
     deps.with {
         api it['x-annotations']
-        api it['commonmark']
+        api it['flexmark']
 
         // @since 4.1.0 to allow PrecomputedTextSetterCompat
         // note that this dependency must be added on a client side explicitly
@@ -35,4 +35,6 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java
index 65db542a..b37ff796 100644
--- a/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java
+++ b/markwon-core/src/main/java/io/noties/markwon/AbstractMarkwonPlugin.java
@@ -5,8 +5,8 @@ import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.core.MarkwonTheme;
 
diff --git a/markwon-core/src/main/java/io/noties/markwon/BlockHandlerDef.java b/markwon-core/src/main/java/io/noties/markwon/BlockHandlerDef.java
index 58567f43..7b5e53eb 100644
--- a/markwon-core/src/main/java/io/noties/markwon/BlockHandlerDef.java
+++ b/markwon-core/src/main/java/io/noties/markwon/BlockHandlerDef.java
@@ -2,7 +2,7 @@ package io.noties.markwon;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 /**
  * @since 4.3.0
diff --git a/markwon-core/src/main/java/io/noties/markwon/Markwon.java b/markwon-core/src/main/java/io/noties/markwon/Markwon.java
index 326a70c2..41ef3577 100644
--- a/markwon-core/src/main/java/io/noties/markwon/Markwon.java
+++ b/markwon-core/src/main/java/io/noties/markwon/Markwon.java
@@ -7,7 +7,7 @@ import android.widget.TextView;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.List;
 
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java
index ae0f2f9d..f6422610 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonBuilderImpl.java
@@ -5,7 +5,7 @@ import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.parser.Parser;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java
index 1e0d7930..59bef452 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonImpl.java
@@ -8,8 +8,14 @@ import android.widget.TextView;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
+
+import com.vladsch.flexmark.ast.Code;
+import com.vladsch.flexmark.ast.Text;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.util.ast.Document;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.ast.NodeVisitor;
+import com.vladsch.flexmark.util.ast.VisitHandler;
 
 import java.util.Collections;
 import java.util.List;
@@ -74,7 +80,7 @@ class MarkwonImpl extends Markwon {
         // @since 4.1.1 obtain visitor via factory
         final MarkwonVisitor visitor = visitorFactory.create();
 
-        node.accept(visitor);
+        visitor.visit(node);
 
         for (MarkwonPlugin plugin : plugins) {
             plugin.afterRender(node, visitor);
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java
index 33527a9b..b3bf169d 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonPlugin.java
@@ -5,8 +5,8 @@ import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.core.CorePlugin;
 import io.noties.markwon.core.MarkwonTheme;
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java
index a987576a..675a718a 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonReducer.java
@@ -2,8 +2,8 @@ package io.noties.markwon;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.LinkReferenceDefinition;
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.ast.Reference;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -51,7 +51,7 @@ public abstract class MarkwonReducer {
                 while (node != null) {
                     // @since 4.5.0 do not include LinkReferenceDefinition node (would result
                     //  in empty textView if rendered in recycler-view)
-                    if (!(node instanceof LinkReferenceDefinition)) {
+                    if (!(node instanceof Reference)) {
                         list.add(node);
                     }
                     temp = node.getNext();
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java
index 43d2b1ec..d0c7c3f4 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactory.java
@@ -3,7 +3,7 @@ package io.noties.markwon;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 /**
  * Class that controls what spans are used for certain Nodes.
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java
index fd7a99d5..ee991fe2 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonSpansFactoryImpl.java
@@ -3,7 +3,7 @@ package io.noties.markwon;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java
index 2f69acf6..48fd0ad8 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitor.java
@@ -3,8 +3,12 @@ package io.noties.markwon;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Node;
-import org.commonmark.node.Visitor;
+import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.util.BlockVisitor;
+import com.vladsch.flexmark.ast.util.InlineVisitor;
+import com.vladsch.flexmark.util.ast.Node;
+
+import org.jetbrains.annotations.NotNull;
 
 /**
  * Configurable visitor of parsed markdown. Allows visiting certain (registered) nodes without
@@ -14,7 +18,7 @@ import org.commonmark.node.Visitor;
  * @see MarkwonPlugin#configureVisitor(Builder)
  * @since 3.0.0
  */
-public interface MarkwonVisitor extends Visitor {
+public interface MarkwonVisitor extends BlockVisitor, InlineVisitor {
 
     /**
      * @see Builder#on(Class, NodeVisitor)
@@ -69,13 +73,6 @@ public interface MarkwonVisitor extends Visitor {
     @NonNull
     SpannableBuilder builder();
 
-    /**
-     * Visits all children of supplied node.
-     *
-     * @param node to visit
-     */
-    void visitChildren(@NonNull Node node);
-
     /**
      * Executes a check if there is further content available.
      *
@@ -166,4 +163,8 @@ public interface MarkwonVisitor extends Visitor {
      * @since 4.3.0
      */
     void blockEnd(@NonNull Node node);
+
+    void visit(@NotNull Node node);
+
+    void visitChildren(Node node);
 }
diff --git a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java
index ce116111..459189af 100644
--- a/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java
+++ b/markwon-core/src/main/java/io/noties/markwon/MarkwonVisitorImpl.java
@@ -3,30 +3,39 @@ package io.noties.markwon;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.BlockQuote;
-import org.commonmark.node.BulletList;
-import org.commonmark.node.Code;
-import org.commonmark.node.CustomBlock;
-import org.commonmark.node.CustomNode;
-import org.commonmark.node.Document;
-import org.commonmark.node.Emphasis;
-import org.commonmark.node.FencedCodeBlock;
-import org.commonmark.node.HardLineBreak;
-import org.commonmark.node.Heading;
-import org.commonmark.node.HtmlBlock;
-import org.commonmark.node.HtmlInline;
-import org.commonmark.node.Image;
-import org.commonmark.node.IndentedCodeBlock;
-import org.commonmark.node.Link;
-import org.commonmark.node.LinkReferenceDefinition;
-import org.commonmark.node.ListItem;
-import org.commonmark.node.Node;
-import org.commonmark.node.OrderedList;
-import org.commonmark.node.Paragraph;
-import org.commonmark.node.SoftLineBreak;
-import org.commonmark.node.StrongEmphasis;
-import org.commonmark.node.Text;
-import org.commonmark.node.ThematicBreak;
+import com.vladsch.flexmark.ast.AutoLink;
+import com.vladsch.flexmark.ast.BlockQuote;
+import com.vladsch.flexmark.ast.BulletList;
+import com.vladsch.flexmark.ast.BulletListItem;
+import com.vladsch.flexmark.ast.Code;
+import com.vladsch.flexmark.ast.Emphasis;
+import com.vladsch.flexmark.ast.FencedCodeBlock;
+import com.vladsch.flexmark.ast.HardLineBreak;
+import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.HtmlBlock;
+import com.vladsch.flexmark.ast.HtmlCommentBlock;
+import com.vladsch.flexmark.ast.HtmlEntity;
+import com.vladsch.flexmark.ast.HtmlInline;
+import com.vladsch.flexmark.ast.HtmlInlineComment;
+import com.vladsch.flexmark.ast.Image;
+import com.vladsch.flexmark.ast.ImageRef;
+import com.vladsch.flexmark.ast.IndentedCodeBlock;
+import com.vladsch.flexmark.ast.Link;
+import com.vladsch.flexmark.ast.LinkRef;
+import com.vladsch.flexmark.ast.ListItem;
+import com.vladsch.flexmark.ast.MailLink;
+import com.vladsch.flexmark.ast.OrderedList;
+import com.vladsch.flexmark.ast.OrderedListItem;
+import com.vladsch.flexmark.ast.Paragraph;
+import com.vladsch.flexmark.ast.Reference;
+import com.vladsch.flexmark.ast.SoftLineBreak;
+import com.vladsch.flexmark.ast.StrongEmphasis;
+import com.vladsch.flexmark.ast.Text;
+import com.vladsch.flexmark.ast.ThematicBreak;
+import com.vladsch.flexmark.ast.util.BlockVisitorExt;
+import com.vladsch.flexmark.ast.util.InlineVisitorExt;
+import com.vladsch.flexmark.util.ast.Document;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -35,7 +44,7 @@ import java.util.Map;
 /**
  * @since 3.0.0
  */
-class MarkwonVisitorImpl implements MarkwonVisitor {
+class MarkwonVisitorImpl extends com.vladsch.flexmark.util.ast.NodeVisitor implements MarkwonVisitor {
 
     private final MarkwonConfiguration configuration;
 
@@ -59,124 +68,169 @@ class MarkwonVisitorImpl implements MarkwonVisitor {
         this.builder = builder;
         this.nodes = nodes;
         this.blockHandler = blockHandler;
+
+        addHandlers(BlockVisitorExt.VISIT_HANDLERS(this));
+        addHandlers(InlineVisitorExt.VISIT_HANDLERS(this));
     }
 
     @Override
     public void visit(BlockQuote blockQuote) {
-        visit((Node) blockQuote);
+        visitImpl(blockQuote);
     }
 
     @Override
     public void visit(BulletList bulletList) {
-        visit((Node) bulletList);
+        visitImpl(bulletList);
+    }
+
+    @Override
+    public void visit(AutoLink autoLink) {
+        visitImpl(autoLink);
     }
 
     @Override
     public void visit(Code code) {
-        visit((Node) code);
+        visitImpl(code);
     }
 
     @Override
     public void visit(Document document) {
-        visit((Node) document);
+        visitImpl(document);
     }
 
     @Override
     public void visit(Emphasis emphasis) {
-        visit((Node) emphasis);
+        visitImpl(emphasis);
     }
 
     @Override
     public void visit(FencedCodeBlock fencedCodeBlock) {
-        visit((Node) fencedCodeBlock);
+        visitImpl(fencedCodeBlock);
+    }
+
+    public void visit(HardLineBreak hardLineBreak) {
+        visitImpl(hardLineBreak);
     }
 
     @Override
-    public void visit(HardLineBreak hardLineBreak) {
-        visit((Node) hardLineBreak);
+    public void visit(HtmlEntity node) {
+        visitImpl(node);
     }
 
     @Override
     public void visit(Heading heading) {
-        visit((Node) heading);
+        visitImpl(heading);
     }
 
     @Override
     public void visit(ThematicBreak thematicBreak) {
-        visit((Node) thematicBreak);
+        visitImpl(thematicBreak);
     }
 
     @Override
     public void visit(HtmlInline htmlInline) {
-        visit((Node) htmlInline);
+        visitImpl(htmlInline);
+    }
+
+    @Override
+    public void visit(HtmlInlineComment node) {
+        visitImpl(node);
     }
 
     @Override
     public void visit(HtmlBlock htmlBlock) {
-        visit((Node) htmlBlock);
+        visitImpl(htmlBlock);
     }
 
+    @Override
+    public void visit(HtmlCommentBlock node) {
+        visitImpl(node);
+    }
+
+    /**
+     * ![Alt text](/path/to/img.jpg "Optional title")
+     */
     @Override
     public void visit(Image image) {
-        visit((Node) image);
+        visitImpl(image);
+    }
+
+    /**
+     * This is a ![foo][bar] image.
+     * [bar]: /url/of/bar.jpg "optional title attribute"
+     */
+    @Override
+    public void visit(ImageRef imageRef) {
+        visitImpl(imageRef);
     }
 
     @Override
     public void visit(IndentedCodeBlock indentedCodeBlock) {
-        visit((Node) indentedCodeBlock);
+        visitImpl(indentedCodeBlock);
+    }
+
+
+//    @Override
+//    public void visit(ListItem listItem) {
+//        visitImpl(listItem);
+//    }
+
+    @Override
+    public void visit(BulletListItem listItem) {
+        visitImpl(listItem);
+    }
+
+    @Override
+    public void visit(OrderedListItem listItem) {
+        visitImpl(listItem);
     }
 
     @Override
     public void visit(Link link) {
-        visit((Node) link);
+        visitImpl(link);
     }
 
     @Override
-    public void visit(ListItem listItem) {
-        visit((Node) listItem);
+    public void visit(LinkRef node) {
+        visitImpl(node);
+    }
+
+    @Override
+    public void visit(MailLink node) {
+        visitImpl(node);
     }
 
     @Override
     public void visit(OrderedList orderedList) {
-        visit((Node) orderedList);
+        visitImpl(orderedList);
     }
 
     @Override
     public void visit(Paragraph paragraph) {
-        visit((Node) paragraph);
+        visitImpl(paragraph);
+    }
+
+    @Override
+    public void visit(Reference node) {
+        // Reference 需要和 ImageRef,LinkRef配合使用,因为这些都是指向 Reference,再由Reference指向真正的地址
     }
 
     @Override
     public void visit(SoftLineBreak softLineBreak) {
-        visit((Node) softLineBreak);
+        visitImpl(softLineBreak);
     }
 
     @Override
     public void visit(StrongEmphasis strongEmphasis) {
-        visit((Node) strongEmphasis);
+        visitImpl(strongEmphasis);
     }
 
     @Override
     public void visit(Text text) {
-        visit((Node) text);
+        visitImpl(text);
     }
 
-    @Override
-    public void visit(LinkReferenceDefinition linkReferenceDefinition) {
-        visit((Node) linkReferenceDefinition);
-    }
-
-    @Override
-    public void visit(CustomBlock customBlock) {
-        visit((Node) customBlock);
-    }
-
-    @Override
-    public void visit(CustomNode customNode) {
-        visit((Node) customNode);
-    }
-
-    private void visit(@NonNull Node node) {
+    private void visitImpl(@NonNull Node node) {
         //noinspection unchecked
         final NodeVisitor<Node> nodeVisitor = (NodeVisitor<Node>) nodes.get(node.getClass());
         if (nodeVisitor != null) {
@@ -204,17 +258,6 @@ class MarkwonVisitorImpl implements MarkwonVisitor {
         return builder;
     }
 
-    @Override
-    public void visitChildren(@NonNull Node parent) {
-        Node node = parent.getFirstChild();
-        while (node != null) {
-            // A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
-            // node after visiting it. So get the next node before visiting.
-            Node next = node.getNext();
-            node.accept(this);
-            node = next;
-        }
-    }
 
     @Override
     public boolean hasNext(@NonNull Node node) {
diff --git a/markwon-core/src/main/java/io/noties/markwon/SoftBreakAddsNewLinePlugin.java b/markwon-core/src/main/java/io/noties/markwon/SoftBreakAddsNewLinePlugin.java
index 9c7572fb..dee5451a 100644
--- a/markwon-core/src/main/java/io/noties/markwon/SoftBreakAddsNewLinePlugin.java
+++ b/markwon-core/src/main/java/io/noties/markwon/SoftBreakAddsNewLinePlugin.java
@@ -2,7 +2,7 @@ package io.noties.markwon;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.SoftLineBreak;
+import com.vladsch.flexmark.ast.SoftLineBreak;
 
 /**
  * @since 4.3.0
diff --git a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java
index 4961505a..d7bfc969 100644
--- a/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java
+++ b/markwon-core/src/main/java/io/noties/markwon/core/CorePlugin.java
@@ -9,27 +9,27 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.commonmark.node.Block;
-import org.commonmark.node.BlockQuote;
-import org.commonmark.node.BulletList;
-import org.commonmark.node.Code;
-import org.commonmark.node.Emphasis;
-import org.commonmark.node.FencedCodeBlock;
-import org.commonmark.node.HardLineBreak;
-import org.commonmark.node.Heading;
-import org.commonmark.node.HtmlBlock;
-import org.commonmark.node.Image;
-import org.commonmark.node.IndentedCodeBlock;
-import org.commonmark.node.Link;
-import org.commonmark.node.ListBlock;
-import org.commonmark.node.ListItem;
-import org.commonmark.node.Node;
-import org.commonmark.node.OrderedList;
-import org.commonmark.node.Paragraph;
-import org.commonmark.node.SoftLineBreak;
-import org.commonmark.node.StrongEmphasis;
-import org.commonmark.node.Text;
-import org.commonmark.node.ThematicBreak;
+import com.vladsch.flexmark.ast.BlockQuote;
+import com.vladsch.flexmark.ast.BulletList;
+import com.vladsch.flexmark.ast.Code;
+import com.vladsch.flexmark.ast.Emphasis;
+import com.vladsch.flexmark.ast.FencedCodeBlock;
+import com.vladsch.flexmark.ast.HardLineBreak;
+import com.vladsch.flexmark.ast.Heading;
+import com.vladsch.flexmark.ast.HtmlBlock;
+import com.vladsch.flexmark.ast.Image;
+import com.vladsch.flexmark.ast.IndentedCodeBlock;
+import com.vladsch.flexmark.ast.Link;
+import com.vladsch.flexmark.ast.ListBlock;
+import com.vladsch.flexmark.ast.ListItem;
+import com.vladsch.flexmark.ast.OrderedList;
+import com.vladsch.flexmark.ast.Paragraph;
+import com.vladsch.flexmark.ast.SoftLineBreak;
+import com.vladsch.flexmark.ast.StrongEmphasis;
+import com.vladsch.flexmark.ast.Text;
+import com.vladsch.flexmark.ast.ThematicBreak;
+import com.vladsch.flexmark.util.ast.Block;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -212,8 +212,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
             @Override
             public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) {
 
-                final String literal = text.getLiteral();
-
+                String literal = text.toAstString(true);
                 visitor.builder().append(literal);
 
                 // @since 4.0.0
@@ -278,7 +277,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
                 // unfortunately we cannot use this for multiline code as we cannot control where a new line break will be inserted
                 visitor.builder()
                         .append('\u00a0')
-                        .append(code.getLiteral())
+                        .append(code.toAstString(true))
                         .append('\u00a0');
 
                 visitor.setSpansForNodeOptional(code, length);
@@ -290,7 +289,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
         builder.on(FencedCodeBlock.class, new MarkwonVisitor.NodeVisitor<FencedCodeBlock>() {
             @Override
             public void visit(@NonNull MarkwonVisitor visitor, @NonNull FencedCodeBlock fencedCodeBlock) {
-                visitCodeBlock(visitor, fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock);
+                visitCodeBlock(visitor, fencedCodeBlock.getInfo().unescape(), fencedCodeBlock.toAstString(true), fencedCodeBlock);
             }
         });
     }
@@ -299,7 +298,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
         builder.on(IndentedCodeBlock.class, new MarkwonVisitor.NodeVisitor<IndentedCodeBlock>() {
             @Override
             public void visit(@NonNull MarkwonVisitor visitor, @NonNull IndentedCodeBlock indentedCodeBlock) {
-                visitCodeBlock(visitor, null, indentedCodeBlock.getLiteral(), indentedCodeBlock);
+                visitCodeBlock(visitor, null, indentedCodeBlock.toAstString(true), indentedCodeBlock);
             }
         });
     }
@@ -335,7 +334,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
 
                 final String destination = configuration
                         .imageDestinationProcessor()
-                        .process(image.getDestination());
+                        .process(image.getUrl().unescape());
 
                 final RenderProps props = visitor.renderProps();
 
@@ -538,7 +537,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
                 final int length = visitor.length();
                 visitor.visitChildren(link);
 
-                final String destination = link.getDestination();
+                final String destination = link.getUrl().unescape();
 
                 CoreProps.LINK_DESTINATION.set(visitor.renderProps(), destination);
 
diff --git a/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java b/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java
index 6a27599e..be944b9e 100644
--- a/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java
+++ b/markwon-core/src/main/java/io/noties/markwon/core/SimpleBlockNodeVisitor.java
@@ -2,7 +2,7 @@ package io.noties.markwon.core;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.MarkwonVisitor;
 
diff --git a/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java
index 5a7dd839..69603b2a 100644
--- a/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java
+++ b/markwon-core/src/main/java/io/noties/markwon/syntax/SyntaxHighlight.java
@@ -3,6 +3,7 @@ package io.noties.markwon.syntax;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+
 @SuppressWarnings("WeakerAccess")
 public interface SyntaxHighlight {
 
diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java b/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java
index e06194b8..a950ff40 100644
--- a/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java
+++ b/markwon-core/src/main/java/io/noties/markwon/utils/DumpNodes.java
@@ -4,8 +4,8 @@ import androidx.annotation.CheckResult;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Node;
-import org.commonmark.node.Visitor;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.ast.Visitor;
 
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
@@ -70,7 +70,8 @@ public abstract class DumpNodes {
                         return null;
                     }
                 });
-        node.accept(visitor);
+        visitor.visit(node);
+        //node.accept(visitor);
         return builder.toString();
     }
 
@@ -104,7 +105,7 @@ public abstract class DumpNodes {
             // A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
             // node after visiting it. So get the next node before visiting.
             Node next = node.getNext();
-            node.accept(visitor);
+            visitor.visit(node);
             node = next;
         }
     }
diff --git a/markwon-core/src/main/java/io/noties/markwon/utils/ParserUtils.java b/markwon-core/src/main/java/io/noties/markwon/utils/ParserUtils.java
index d697d26f..f400e70e 100644
--- a/markwon-core/src/main/java/io/noties/markwon/utils/ParserUtils.java
+++ b/markwon-core/src/main/java/io/noties/markwon/utils/ParserUtils.java
@@ -2,7 +2,7 @@ package io.noties.markwon.utils;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 /**
  * @since 4.6.0
diff --git a/markwon-editor/build.gradle b/markwon-editor/build.gradle
index 884f6fb6..bd288b5f 100644
--- a/markwon-editor/build.gradle
+++ b/markwon-editor/build.gradle
@@ -28,4 +28,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-ext-latex/build.gradle b/markwon-ext-latex/build.gradle
index b0d3fc92..6ea48452 100644
--- a/markwon-ext-latex/build.gradle
+++ b/markwon-ext-latex/build.gradle
@@ -16,7 +16,6 @@ android {
 dependencies {
 
     api project(':markwon-core')
-    api project(':markwon-inline-parser')
 
     api deps['jlatexmath-android']
 
@@ -27,4 +26,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java
deleted file mode 100644
index 4066caba..00000000
--- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlock.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import org.commonmark.node.CustomBlock;
-
-public class JLatexMathBlock extends CustomBlock {
-
-    private String latex;
-
-    public String latex() {
-        return latex;
-    }
-
-    public void latex(String latex) {
-        this.latex = latex;
-    }
-}
diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java
deleted file mode 100644
index cf212e32..00000000
--- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParser.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.internal.util.Parsing;
-import org.commonmark.node.Block;
-import org.commonmark.parser.block.AbstractBlockParser;
-import org.commonmark.parser.block.AbstractBlockParserFactory;
-import org.commonmark.parser.block.BlockContinue;
-import org.commonmark.parser.block.BlockStart;
-import org.commonmark.parser.block.MatchedBlockParser;
-import org.commonmark.parser.block.ParserState;
-
-/**
- * @since 4.3.0 (although there was a class with the same name,
- * which is renamed now to {@link JLatexMathBlockParserLegacy})
- */
-class JLatexMathBlockParser extends AbstractBlockParser {
-
-    private static final char DOLLAR = '$';
-    private static final char SPACE = ' ';
-
-    private final JLatexMathBlock block = new JLatexMathBlock();
-
-    private final StringBuilder builder = new StringBuilder();
-
-    private final int signs;
-
-    JLatexMathBlockParser(int signs) {
-        this.signs = signs;
-    }
-
-    @Override
-    public Block getBlock() {
-        return block;
-    }
-
-    @Override
-    public BlockContinue tryContinue(ParserState parserState) {
-        final int nextNonSpaceIndex = parserState.getNextNonSpaceIndex();
-        final CharSequence line = parserState.getLine();
-        final int length = line.length();
-
-        // check for closing
-        if (parserState.getIndent() < Parsing.CODE_BLOCK_INDENT) {
-            if (consume(DOLLAR, line, nextNonSpaceIndex, length) == signs) {
-                // okay, we have our number of signs
-                // let's consume spaces until the end
-                if (Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length) == length) {
-                    return BlockContinue.finished();
-                }
-            }
-        }
-
-        return BlockContinue.atIndex(parserState.getIndex());
-    }
-
-    @Override
-    public void addLine(CharSequence line) {
-        builder.append(line);
-        builder.append('\n');
-    }
-
-    @Override
-    public void closeBlock() {
-        block.latex(builder.toString());
-    }
-
-    public static class Factory extends AbstractBlockParserFactory {
-
-        @Override
-        public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
-
-            // let's define the spec:
-            //  * 0-3 spaces before are allowed (Parsing.CODE_BLOCK_INDENT = 4)
-            //  * 2+ subsequent `$` signs
-            //  * any optional amount of spaces
-            //  * new line
-            //  * block is closed when the same amount of opening signs is met
-
-            final int indent = state.getIndent();
-
-            // check if it's an indented code block
-            if (indent >= Parsing.CODE_BLOCK_INDENT) {
-                return BlockStart.none();
-            }
-
-            final int nextNonSpaceIndex = state.getNextNonSpaceIndex();
-            final CharSequence line = state.getLine();
-            final int length = line.length();
-
-            final int signs = consume(DOLLAR, line, nextNonSpaceIndex, length);
-
-            // 2 is minimum
-            if (signs < 2) {
-                return BlockStart.none();
-            }
-
-            // consume spaces until the end of the line, if any other content is found -> NONE
-            if (Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length) != length) {
-                return BlockStart.none();
-            }
-
-            return BlockStart.of(new JLatexMathBlockParser(signs))
-                    .atIndex(length + 1);
-        }
-    }
-
-    @SuppressWarnings("SameParameterValue")
-    private static int consume(char c, @NonNull CharSequence line, int start, int end) {
-        for (int i = start; i < end; i++) {
-            if (c != line.charAt(i)) {
-                return i - start;
-            }
-        }
-        // all consumed
-        return end - start;
-    }
-}
diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParserLegacy.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParserLegacy.java
deleted file mode 100644
index 9b4565bc..00000000
--- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathBlockParserLegacy.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import org.commonmark.node.Block;
-import org.commonmark.parser.block.AbstractBlockParser;
-import org.commonmark.parser.block.AbstractBlockParserFactory;
-import org.commonmark.parser.block.BlockContinue;
-import org.commonmark.parser.block.BlockStart;
-import org.commonmark.parser.block.MatchedBlockParser;
-import org.commonmark.parser.block.ParserState;
-
-/**
- * @since 4.3.0 (although it is just renamed parser from previous versions)
- */
-class JLatexMathBlockParserLegacy extends AbstractBlockParser {
-
-    private final JLatexMathBlock block = new JLatexMathBlock();
-
-    private final StringBuilder builder = new StringBuilder();
-
-    private boolean isClosed;
-
-    @Override
-    public Block getBlock() {
-        return block;
-    }
-
-    @Override
-    public BlockContinue tryContinue(ParserState parserState) {
-
-        if (isClosed) {
-            return BlockContinue.finished();
-        }
-
-        return BlockContinue.atIndex(parserState.getIndex());
-    }
-
-    @Override
-    public void addLine(CharSequence line) {
-
-        if (builder.length() > 0) {
-            builder.append('\n');
-        }
-
-        builder.append(line);
-
-        final int length = builder.length();
-        if (length > 1) {
-            isClosed = '$' == builder.charAt(length - 1)
-                    && '$' == builder.charAt(length - 2);
-            if (isClosed) {
-                builder.replace(length - 2, length, "");
-            }
-        }
-    }
-
-    @Override
-    public void closeBlock() {
-        block.latex(builder.toString());
-    }
-
-    public static class Factory extends AbstractBlockParserFactory {
-
-        @Override
-        public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
-
-            final CharSequence line = state.getLine();
-            final int length = line != null
-                    ? line.length()
-                    : 0;
-
-            if (length > 1) {
-                if ('$' == line.charAt(0)
-                        && '$' == line.charAt(1)) {
-                    return BlockStart.of(new JLatexMathBlockParserLegacy())
-                            .atIndex(state.getIndex() + 2);
-                }
-            }
-
-            return BlockStart.none();
-        }
-    }
-}
diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathInlineProcessor.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathInlineProcessor.java
deleted file mode 100644
index d368778c..00000000
--- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathInlineProcessor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import androidx.annotation.Nullable;
-
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-import io.noties.markwon.inlineparser.InlineProcessor;
-
-/**
- * @since 4.3.0
- */
-class JLatexMathInlineProcessor extends InlineProcessor {
-
-    private static final Pattern RE = Pattern.compile("(\\${2})([\\s\\S]+?)\\1");
-
-    @Override
-    public char specialCharacter() {
-        return '$';
-    }
-
-    @Nullable
-    @Override
-    protected Node parse() {
-
-        final String latex = match(RE);
-        if (latex == null) {
-            return null;
-        }
-
-        final JLatexMathNode node = new JLatexMathNode();
-        node.latex(latex.substring(2, latex.length() - 2));
-        return node;
-    }
-}
diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathNode.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathNode.java
deleted file mode 100644
index 46948cc5..00000000
--- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathNode.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import org.commonmark.node.CustomNode;
-
-/**
- * @since 4.3.0
- */
-public class JLatexMathNode extends CustomNode {
-
-    private String latex;
-
-    public String latex() {
-        return latex;
-    }
-
-    public void latex(String latex) {
-        this.latex = latex;
-    }
-}
diff --git a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java
index dd8a606e..b9f7e975 100644
--- a/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java
+++ b/markwon-ext-latex/src/main/java/io/noties/markwon/ext/latex/JLatexMathPlugin.java
@@ -14,8 +14,11 @@ import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
 
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.ext.gitlab.GitLabExtension;
+import com.vladsch.flexmark.ext.gitlab.GitLabInlineMath;
+import com.vladsch.flexmark.parser.Parser;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
@@ -31,7 +34,6 @@ import io.noties.markwon.image.AsyncDrawableScheduler;
 import io.noties.markwon.image.AsyncDrawableSpan;
 import io.noties.markwon.image.DrawableUtils;
 import io.noties.markwon.image.ImageSizeResolver;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
 import ru.noties.jlatexmath.JLatexMathDrawable;
 
 /**
@@ -117,8 +119,6 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
 
         // @since 4.3.0
         final boolean blocksEnabled;
-        final boolean blocksLegacy;
-        final boolean inlinesEnabled;
 
         // @since 4.3.0
         final ErrorHandler errorHandler;
@@ -128,8 +128,6 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
         Config(@NonNull Builder builder) {
             this.theme = builder.theme.build();
             this.blocksEnabled = builder.blocksEnabled;
-            this.blocksLegacy = builder.blocksLegacy;
-            this.inlinesEnabled = builder.inlinesEnabled;
             this.errorHandler = builder.errorHandler;
             // @since 4.0.0
             ExecutorService executorService = builder.executorService;
@@ -155,59 +153,34 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
         this.inlineImageSizeResolver = new InlineImageSizeResolver();
     }
 
-    @Override
-    public void configure(@NonNull Registry registry) {
-        if (config.inlinesEnabled) {
-            registry.require(MarkwonInlineParserPlugin.class)
-                    .factoryBuilder()
-                    .addInlineProcessor(new JLatexMathInlineProcessor());
-        }
-    }
-
     @Override
     public void configureParser(@NonNull Parser.Builder builder) {
-        // @since 4.3.0
+        builder.extensions(Collections.singleton(GitLabExtension.create()));
         if (config.blocksEnabled) {
-            if (config.blocksLegacy) {
-                builder.customBlockParserFactory(new JLatexMathBlockParserLegacy.Factory());
-            } else {
-                builder.customBlockParserFactory(new JLatexMathBlockParser.Factory());
-            }
+            builder.set(GitLabExtension.RENDER_BLOCK_MATH, true);
         }
     }
 
     @Override
     public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
-        addBlockVisitor(builder);
-        addInlineVisitor(builder);
-    }
-
-    private void addBlockVisitor(@NonNull MarkwonVisitor.Builder builder) {
-        if (!config.blocksEnabled) {
-            return;
-        }
-
-        builder.on(JLatexMathBlock.class, new MarkwonVisitor.NodeVisitor<JLatexMathBlock>() {
+        builder.on(GitLabInlineMath.class, new MarkwonVisitor.NodeVisitor<GitLabInlineMath>() {
             @Override
-            public void visit(@NonNull MarkwonVisitor visitor, @NonNull JLatexMathBlock jLatexMathBlock) {
-
-                visitor.blockStart(jLatexMathBlock);
-
-                final String latex = jLatexMathBlock.latex();
-
+            public void visit(@NonNull MarkwonVisitor visitor, @NonNull GitLabInlineMath gitLabInlineMath) {
+                if (config.blocksEnabled) visitor.blockStart(gitLabInlineMath);
+                final String tex = gitLabInlineMath.getText().unescape();
                 final int length = visitor.length();
 
                 // @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
                 // because Android will draw formula for each line of text, thus
                 // leading to formula duplicated (drawn on each line of text)
-                visitor.builder().append(prepareLatexTextPlaceholder(latex));
+                visitor.builder().append(prepareLatexTextPlaceholder(tex));
 
                 final MarkwonConfiguration configuration = visitor.configuration();
 
                 final AsyncDrawableSpan span = new JLatexAsyncDrawableSpan(
                         configuration.theme(),
                         new JLatextAsyncDrawable(
-                                latex,
+                                tex,
                                 jLatextAsyncDrawableLoader,
                                 jLatexBlockImageSizeResolver,
                                 null,
@@ -217,43 +190,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
 
                 visitor.setSpans(length, span);
 
-                visitor.blockEnd(jLatexMathBlock);
-            }
-        });
-    }
-
-    private void addInlineVisitor(@NonNull MarkwonVisitor.Builder builder) {
-
-        if (!config.inlinesEnabled) {
-            return;
-        }
-
-        builder.on(JLatexMathNode.class, new MarkwonVisitor.NodeVisitor<JLatexMathNode>() {
-            @Override
-            public void visit(@NonNull MarkwonVisitor visitor, @NonNull JLatexMathNode jLatexMathNode) {
-                final String latex = jLatexMathNode.latex();
-
-                final int length = visitor.length();
-
-                // @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
-                // because Android will draw formula for each line of text, thus
-                // leading to formula duplicated (drawn on each line of text)
-                visitor.builder().append(prepareLatexTextPlaceholder(latex));
-
-                final MarkwonConfiguration configuration = visitor.configuration();
-
-                final AsyncDrawableSpan span = new JLatexInlineAsyncDrawableSpan(
-                        configuration.theme(),
-                        new JLatextAsyncDrawable(
-                                latex,
-                                jLatextAsyncDrawableLoader,
-                                inlineImageSizeResolver,
-                                null,
-                                false),
-                        config.theme.inlineTextColor()
-                );
-
-                visitor.setSpans(length, span);
+                if (config.blocksEnabled) visitor.blockEnd(gitLabInlineMath);
             }
         });
     }
@@ -310,16 +247,6 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
             return this;
         }
 
-        /**
-         * @param blocksLegacy indicates if blocks should be handled in legacy mode ({@code pre 4.3.0})
-         * @since 4.3.0
-         */
-        @NonNull
-        public Builder blocksLegacy(boolean blocksLegacy) {
-            this.blocksLegacy = blocksLegacy;
-            return this;
-        }
-
         /**
          * @param inlinesEnabled indicates if inline parsing should be enabled.
          *                       NB, this requires `MarkwonInlineParserPlugin` to be used when creating `MarkwonInstance`
diff --git a/markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathBlockParserTest.java b/markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathBlockParserTest.java
deleted file mode 100644
index b1587e1d..00000000
--- a/markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathBlockParserTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.internal.BlockContinueImpl;
-import org.commonmark.internal.BlockStartImpl;
-import org.commonmark.internal.util.Parsing;
-import org.commonmark.parser.block.BlockStart;
-import org.commonmark.parser.block.ParserState;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class JLatexMathBlockParserTest {
-
-    private static final String[] NO_MATCH = {
-            " ",
-            "   ",
-            "    ",
-            "$ ",
-            " $ $",
-            "-$$",
-            "  -$$",
-            "$$-",
-            " $$  -",
-            "  $$        -",
-            "$$$          -"
-    };
-
-    private static final String[] MATCH = {
-            "$$",
-            " $$",
-            "  $$",
-            "   $$",
-            "$$                 ",
-            " $$   ",
-            "  $$       ",
-            "   $$                                                    ",
-            "$$$",
-            " $$$",
-            "   $$$",
-            "$$$$",
-            "   $$$$",
-            "$$$$$$$$$$$$$$$$$$$$$",
-            " $$$$$$$$$$$$$$$$$$$$$",
-            "  $$$$$$$$$$$$$$$$$$$$$",
-            "   $$$$$$$$$$$$$$$$$$$$$"
-    };
-
-    private JLatexMathBlockParser.Factory factory;
-
-    @Before
-    public void before() {
-        factory = new JLatexMathBlockParser.Factory();
-    }
-
-    @Test
-    public void factory_indentBlock() {
-        // when state indent is greater than block -> nono
-
-        final ParserState state = mock(ParserState.class);
-        when(state.getIndent()).thenReturn(Parsing.CODE_BLOCK_INDENT);
-
-        // hm, interesting, `BlockStart.none()` actually returns null
-        final BlockStart start = factory.tryStart(state, null);
-        assertNull(start);
-    }
-
-    @Test
-    public void factory_noMatch() {
-
-        for (String line : NO_MATCH) {
-            final ParserState state = createState(line);
-
-            assertNull(factory.tryStart(state, null));
-        }
-    }
-
-    @Test
-    public void factory_match() {
-
-        for (String line : MATCH) {
-            final ParserState state = createState(line);
-
-            final BlockStart start = factory.tryStart(state, null);
-            assertNotNull(start);
-
-            // hm...
-            final BlockStartImpl impl = (BlockStartImpl) start;
-            assertEquals(quote(line), line.length() + 1, impl.getNewIndex());
-        }
-    }
-
-    @Test
-    public void finish() {
-
-        for (String line : MATCH) {
-            final ParserState state = createState(line);
-
-            // we will have 2 checks here:
-            //  * must pass for correct length
-            //  * must fail for incorrect
-
-            final int count = countDollarSigns(line);
-
-            // pass
-            {
-                final JLatexMathBlockParser parser = new JLatexMathBlockParser(count);
-                final BlockContinueImpl impl = (BlockContinueImpl) parser.tryContinue(state);
-                assertTrue(quote(line), impl.isFinalize());
-            }
-
-            // fail (in terms of closing, not failing test)
-            {
-                final JLatexMathBlockParser parser = new JLatexMathBlockParser(count + 1);
-                final BlockContinueImpl impl = (BlockContinueImpl) parser.tryContinue(state);
-                assertFalse(quote(line), impl.isFinalize());
-            }
-        }
-    }
-
-    @Test
-    public void finish_noMatch() {
-        for (String line : NO_MATCH) {
-            final ParserState state = createState(line);
-            // doesn't matter
-            final int count = 2;
-            final JLatexMathBlockParser parser = new JLatexMathBlockParser(count);
-            final BlockContinueImpl impl = (BlockContinueImpl) parser.tryContinue(state);
-            assertFalse(quote(line), impl.isFinalize());
-        }
-    }
-
-    @NonNull
-    private static ParserState createState(@NonNull String line) {
-
-        final ParserState state = mock(ParserState.class);
-
-        int i = 0;
-        for (int length = line.length(); i < length; i++) {
-            if (' ' != line.charAt(i)) {
-                // previous is the last space
-                break;
-            }
-        }
-
-        when(state.getIndent()).thenReturn(i);
-        when(state.getNextNonSpaceIndex()).thenReturn(i);
-        when(state.getLine()).thenReturn(line);
-
-        return state;
-    }
-
-    private static int countDollarSigns(@NonNull String line) {
-        int count = 0;
-        for (int i = 0, length = line.length(); i < length; i++) {
-            if ('$' == line.charAt(i)) count += 1;
-        }
-        return count;
-    }
-
-    @NonNull
-    private static String quote(@NonNull String s) {
-        return '\'' + s + '\'';
-    }
-}
\ No newline at end of file
diff --git a/markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathPluginTest.java b/markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathPluginTest.java
deleted file mode 100644
index a2467ae3..00000000
--- a/markwon-ext-latex/src/test/java/io/noties/markwon/ext/latex/JLatexMathPluginTest.java
+++ /dev/null
@@ -1,230 +0,0 @@
-package io.noties.markwon.ext.latex;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.parser.Parser;
-import org.commonmark.parser.block.BlockParserFactory;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-
-import io.noties.markwon.MarkwonConfiguration;
-import io.noties.markwon.MarkwonPlugin;
-import io.noties.markwon.MarkwonVisitor;
-import io.noties.markwon.SpannableBuilder;
-import io.noties.markwon.inlineparser.InlineProcessor;
-import io.noties.markwon.inlineparser.MarkwonInlineParser;
-import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class JLatexMathPluginTest {
-
-    @Test
-    public void latex_text_placeholder() {
-        // text placeholder cannot have new-line characters and should be trimmed from ends
-
-        final String[] in = {
-                "hello",
-                "he\nllo",
-                " hello\n\n",
-                "\n\nhello\n\n",
-                "\n",
-                " \nhello\n "
-        };
-
-        for (String latex : in) {
-            final String placeholder = JLatexMathPlugin.prepareLatexTextPlaceholder(latex);
-            assertTrue(placeholder, placeholder.indexOf('\n') < 0);
-            if (placeholder.length() > 0) {
-                assertFalse(placeholder, Character.isWhitespace(placeholder.charAt(0)));
-                assertFalse(placeholder, Character.isWhitespace(placeholder.charAt(placeholder.length() - 1)));
-            }
-        }
-    }
-
-    @Test
-    public void block_parser_registered() {
-        final JLatexMathPlugin plugin = JLatexMathPlugin.create(0);
-        final Parser.Builder builder = mock(Parser.Builder.class);
-        plugin.configureParser(builder);
-        verify(builder, times(1)).customBlockParserFactory(any(BlockParserFactory.class));
-    }
-
-    @Test
-    public void visitor_registered() {
-        final JLatexMathPlugin plugin = JLatexMathPlugin.create(0);
-        final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
-        plugin.configureVisitor(builder);
-        //noinspection unchecked
-        verify(builder, times(1))
-                .on(eq(JLatexMathBlock.class), any(MarkwonVisitor.NodeVisitor.class));
-    }
-
-    @Test
-    public void visit() {
-        final JLatexMathPlugin plugin = JLatexMathPlugin.create(0, new JLatexMathPlugin.BuilderConfigure() {
-            @Override
-            public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) {
-                // no async in test (nooped for this test)
-                builder.executorService(mock(ExecutorService.class));
-            }
-        });
-        final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
-        final ArgumentCaptor<MarkwonVisitor.NodeVisitor> captor =
-                ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class);
-        plugin.configureVisitor(builder);
-        //noinspection unchecked
-        verify(builder, times(1))
-                .on(eq(JLatexMathBlock.class), captor.capture());
-        final MarkwonVisitor.NodeVisitor nodeVisitor = captor.getValue();
-
-        final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
-        final JLatexMathBlock block = mock(JLatexMathBlock.class);
-        when(block.latex()).thenReturn(" first\nsecond\n ");
-
-        final SpannableBuilder spannableBuilder = mock(SpannableBuilder.class);
-        when(visitor.builder()).thenReturn(spannableBuilder);
-        when(visitor.configuration()).thenReturn(mock(MarkwonConfiguration.class));
-
-        //noinspection unchecked
-        nodeVisitor.visit(visitor, block);
-
-        verify(block, times(1)).latex();
-        verify(visitor, times(1)).length();
-
-        final ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
-        verify(spannableBuilder, times(1)).append(stringArgumentCaptor.capture());
-
-        final String placeholder = stringArgumentCaptor.getValue();
-        assertTrue(placeholder, placeholder.indexOf('\n') < 0);
-
-        verify(visitor, times(1)).setSpans(eq(0), any());
-    }
-
-    @Test
-    public void legacy() {
-        // if render mode is legacy:
-        //  - no inline plugin is required,
-        //  - parser has legacy block parser factory
-        //  - no inline node is registered (node)
-
-        final JLatexMathPlugin plugin = JLatexMathPlugin.create(1, new JLatexMathPlugin.BuilderConfigure() {
-            @Override
-            public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) {
-                builder.blocksLegacy(true);
-                builder.inlinesEnabled(false);
-            }
-        });
-
-        // registry
-        {
-            final MarkwonPlugin.Registry registry = mock(MarkwonPlugin.Registry.class);
-            plugin.configure(registry);
-            verify(registry, never()).require(any(Class.class));
-        }
-
-        // parser
-        {
-            final Parser.Builder builder = mock(Parser.Builder.class);
-            plugin.configureParser(builder);
-
-            final ArgumentCaptor<BlockParserFactory> captor =
-                    ArgumentCaptor.forClass(BlockParserFactory.class);
-            verify(builder, times(1)).customBlockParserFactory(captor.capture());
-            final BlockParserFactory factory = captor.getValue();
-            assertTrue(factory.getClass().getName(), factory instanceof JLatexMathBlockParserLegacy.Factory);
-        }
-
-        // visitor
-        {
-            final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
-            plugin.configureVisitor(builder);
-
-            final ArgumentCaptor<Class> captor = ArgumentCaptor.forClass(Class.class);
-            verify(builder, times(1)).on(captor.capture(), any(MarkwonVisitor.NodeVisitor.class));
-
-            assertEquals(JLatexMathBlock.class, captor.getValue());
-        }
-    }
-
-    @Test
-    public void blocks_inlines_implicit() {
-        final JLatexMathPlugin plugin = JLatexMathPlugin.create(1);
-        final JLatexMathPlugin.Config config = plugin.config;
-        assertTrue("blocksEnabled", config.blocksEnabled);
-        assertFalse("blocksLegacy", config.blocksLegacy);
-        assertFalse("inlinesEnabled", config.inlinesEnabled);
-    }
-
-    @Test
-    public void blocks_inlines() {
-        final JLatexMathPlugin plugin = JLatexMathPlugin.create(12, new JLatexMathPlugin.BuilderConfigure() {
-            @Override
-            public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) {
-                builder.inlinesEnabled(true);
-            }
-        });
-
-        // registry
-        {
-            final MarkwonInlineParser.FactoryBuilder factoryBuilder = mock(MarkwonInlineParser.FactoryBuilder.class);
-            final MarkwonInlineParserPlugin inlineParserPlugin = mock(MarkwonInlineParserPlugin.class);
-            final MarkwonPlugin.Registry registry = mock(MarkwonPlugin.Registry.class);
-            when(inlineParserPlugin.factoryBuilder()).thenReturn(factoryBuilder);
-            when(registry.require(eq(MarkwonInlineParserPlugin.class))).thenReturn(inlineParserPlugin);
-            plugin.configure(registry);
-
-            verify(registry, times(1)).require(eq(MarkwonInlineParserPlugin.class));
-            verify(inlineParserPlugin, times(1)).factoryBuilder();
-
-            final ArgumentCaptor<InlineProcessor> captor = ArgumentCaptor.forClass(InlineProcessor.class);
-            verify(factoryBuilder, times(1)).addInlineProcessor(captor.capture());
-
-            final InlineProcessor inlineProcessor = captor.getValue();
-            assertTrue(inlineParserPlugin.getClass().getName(), inlineProcessor instanceof JLatexMathInlineProcessor);
-        }
-
-        // parser
-        {
-            final Parser.Builder builder = mock(Parser.Builder.class);
-            plugin.configureParser(builder);
-
-            final ArgumentCaptor<BlockParserFactory> captor =
-                    ArgumentCaptor.forClass(BlockParserFactory.class);
-            verify(builder, times(1)).customBlockParserFactory(captor.capture());
-            final BlockParserFactory factory = captor.getValue();
-            assertTrue(factory.getClass().getName(), factory instanceof JLatexMathBlockParser.Factory);
-        }
-
-        // visitor
-        {
-            final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
-            plugin.configureVisitor(builder);
-
-            final ArgumentCaptor<Class> captor = ArgumentCaptor.forClass(Class.class);
-            verify(builder, times(2)).on(captor.capture(), any(MarkwonVisitor.NodeVisitor.class));
-
-            final List<Class> nodes = captor.getAllValues();
-            assertEquals(2, nodes.size());
-            assertTrue(nodes.toString(), nodes.contains(JLatexMathNode.class));
-            assertTrue(nodes.toString(), nodes.contains(JLatexMathBlock.class));
-        }
-    }
-}
\ No newline at end of file
diff --git a/markwon-ext-strikethrough/build.gradle b/markwon-ext-strikethrough/build.gradle
index 6cd72e5e..65f48c54 100644
--- a/markwon-ext-strikethrough/build.gradle
+++ b/markwon-ext-strikethrough/build.gradle
@@ -18,8 +18,6 @@ dependencies {
     api project(':markwon-core')
 
     deps.with {
-        api it['commonmark-strikethrough']
-
         // NB! ix-java dependency to be used in tests
         testImplementation it['ix-java']
     }
@@ -32,4 +30,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java b/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java
index f805f612..7efef2e2 100644
--- a/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java
+++ b/markwon-ext-strikethrough/src/main/java/io/noties/markwon/ext/strikethrough/StrikethroughPlugin.java
@@ -4,9 +4,9 @@ import android.text.style.StrikethroughSpan;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.ext.gfm.strikethrough.Strikethrough;
-import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.ext.gfm.strikethrough.Strikethrough;
+import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
+import com.vladsch.flexmark.parser.Parser;
 
 import java.util.Collections;
 
@@ -18,8 +18,8 @@ import io.noties.markwon.RenderProps;
 import io.noties.markwon.SpanFactory;
 
 /**
- * Plugin to add strikethrough markdown feature. This plugin will extend commonmark-java.Parser
- * with strikethrough extension, add SpanFactory and register commonmark-java.Strikethrough node
+ * Plugin to add strikethrough markdown feature. This plugin will extend flexmark.Parser
+ * with strikethrough extension, add SpanFactory and register flexmark.Strikethrough node
  * visitor
  *
  * @see #create()
diff --git a/markwon-ext-tables/build.gradle b/markwon-ext-tables/build.gradle
index ee753b1a..1a0f89aa 100644
--- a/markwon-ext-tables/build.gradle
+++ b/markwon-ext-tables/build.gradle
@@ -11,15 +11,16 @@ android {
         versionCode 1
         versionName version
     }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_11
+        targetCompatibility JavaVersion.VERSION_11
+    }
 }
 
 dependencies {
 
     api project(':markwon-core')
-
-    deps.with {
-        api it['commonmark-table']
-    }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java
index 1d973ddc..1918f6bd 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/Table.java
@@ -5,12 +5,16 @@ import android.text.Spanned;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.ext.gfm.tables.TableBlock;
-import org.commonmark.ext.gfm.tables.TableCell;
-import org.commonmark.ext.gfm.tables.TableHead;
-import org.commonmark.ext.gfm.tables.TableRow;
-import org.commonmark.node.AbstractVisitor;
-import org.commonmark.node.CustomNode;
+import com.vladsch.flexmark.ast.BlockQuote;
+import com.vladsch.flexmark.ast.util.BlockVisitorExt;
+import com.vladsch.flexmark.ast.util.InlineVisitorExt;
+import com.vladsch.flexmark.ext.tables.TableBlock;
+import com.vladsch.flexmark.ext.tables.TableCell;
+import com.vladsch.flexmark.ext.tables.TableHead;
+import com.vladsch.flexmark.ext.tables.TableRow;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.ast.NodeVisitor;
+import com.vladsch.flexmark.util.ast.VisitHandler;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -40,7 +44,8 @@ public class Table {
         final Table table;
 
         final ParseVisitor visitor = new ParseVisitor(markwon);
-        tableBlock.accept(visitor);
+        visitor.visit(tableBlock);
+
         final List<Row> rows = visitor.rows();
 
         if (rows == null) {
@@ -135,7 +140,7 @@ public class Table {
                 '}';
     }
 
-    static class ParseVisitor extends AbstractVisitor {
+    static class ParseVisitor extends NodeVisitor implements TableVisitor{
 
         private final Markwon markwon;
 
@@ -146,6 +151,7 @@ public class Table {
 
         ParseVisitor(@NonNull Markwon markwon) {
             this.markwon = markwon;
+            addHandlers(TableVisitor.VISIT_HANDLERS(this));
         }
 
         @Nullable
@@ -154,44 +160,47 @@ public class Table {
         }
 
         @Override
-        public void visit(CustomNode customNode) {
-
-            if (customNode instanceof TableCell) {
-
-                final TableCell cell = (TableCell) customNode;
-
-                if (pendingRow == null) {
-                    pendingRow = new ArrayList<>(2);
-                }
-
-                pendingRow.add(new Table.Column(alignment(cell.getAlignment()), markwon.render(cell)));
-                pendingRowIsHeader = cell.isHeader();
-
-                return;
+        public void visit(TableCell cell) {
+            if (pendingRow == null) {
+                pendingRow = new ArrayList<>(2);
             }
 
-            if (customNode instanceof TableHead
-                    || customNode instanceof TableRow) {
+            pendingRow.add(new Table.Column(alignment(cell.getAlignment()), markwon.render(cell)));
+            pendingRowIsHeader = cell.isHeader();
+        }
 
-                visitChildren(customNode);
+        @Override
+        public void visit(TableHead head) {
+            visitChildren(head);
 
-                // this can happen, ignore such row
-                if (pendingRow != null && pendingRow.size() > 0) {
-
-                    if (rows == null) {
-                        rows = new ArrayList<>(2);
-                    }
-
-                    rows.add(new Table.Row(pendingRowIsHeader, pendingRow));
+            // this can happen, ignore such row
+            if (pendingRow != null && pendingRow.size() > 0) {
+                if (rows == null) {
+                    rows = new ArrayList<>(2);
                 }
 
-                pendingRow = null;
-                pendingRowIsHeader = false;
-
-                return;
+                rows.add(new Table.Row(pendingRowIsHeader, pendingRow));
             }
 
-            visitChildren(customNode);
+            pendingRow = null;
+            pendingRowIsHeader = false;
+        }
+
+        @Override
+        public void visit(TableRow row) {
+            visitChildren(row);
+
+            // this can happen, ignore such row
+            if (pendingRow != null && pendingRow.size() > 0) {
+                if (rows == null) {
+                    rows = new ArrayList<>(2);
+                }
+
+                rows.add(new Table.Row(pendingRowIsHeader, pendingRow));
+            }
+
+            pendingRow = null;
+            pendingRowIsHeader = false;
         }
 
         @NonNull
@@ -206,5 +215,6 @@ public class Table {
             }
             return out;
         }
+
     }
 }
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
index d5d0f74f..c1b30aef 100644
--- a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TablePlugin.java
@@ -6,14 +6,14 @@ import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.ext.gfm.tables.TableBlock;
-import org.commonmark.ext.gfm.tables.TableBody;
-import org.commonmark.ext.gfm.tables.TableCell;
-import org.commonmark.ext.gfm.tables.TableHead;
-import org.commonmark.ext.gfm.tables.TableRow;
-import org.commonmark.ext.gfm.tables.TablesExtension;
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.ext.tables.TableBlock;
+import com.vladsch.flexmark.ext.tables.TableBody;
+import com.vladsch.flexmark.ext.tables.TableCell;
+import com.vladsch.flexmark.ext.tables.TableHead;
+import com.vladsch.flexmark.ext.tables.TableRow;
+import com.vladsch.flexmark.ext.tables.TablesExtension;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableVisitor.java b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableVisitor.java
new file mode 100644
index 00000000..60322eeb
--- /dev/null
+++ b/markwon-ext-tables/src/main/java/io/noties/markwon/ext/tables/TableVisitor.java
@@ -0,0 +1,28 @@
+package io.noties.markwon.ext.tables;
+
+import com.vladsch.flexmark.ext.tables.TableCell;
+import com.vladsch.flexmark.ext.tables.TableHead;
+import com.vladsch.flexmark.ext.tables.TableRow;
+import com.vladsch.flexmark.util.ast.VisitHandler;
+
+/**
+ * <p>
+ *
+ * @author cpacm 2023/4/4
+ */
+public interface TableVisitor {
+
+    void visit(TableCell node);
+
+    void visit(TableHead head);
+
+    void visit(TableRow row);
+
+    public static <V extends TableVisitor> VisitHandler<?>[] VISIT_HANDLERS(V visitor) {
+        return new VisitHandler<?>[]{
+                new VisitHandler<>(TableCell.class, visitor::visit),
+                new VisitHandler<>(TableHead.class, visitor::visit),
+                new VisitHandler<>(TableRow.class, visitor::visit),
+        };
+    }
+}
diff --git a/markwon-ext-tasklist/build.gradle b/markwon-ext-tasklist/build.gradle
index 315808d4..9f969bbb 100644
--- a/markwon-ext-tasklist/build.gradle
+++ b/markwon-ext-tasklist/build.gradle
@@ -27,4 +27,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java
deleted file mode 100644
index 497bddb2..00000000
--- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListItem.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package io.noties.markwon.ext.tasklist;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.node.CustomBlock;
-
-/**
- * @since 1.0.1
- */
-@SuppressWarnings("WeakerAccess")
-public class TaskListItem extends CustomBlock {
-
-    private final boolean isDone;
-
-    public TaskListItem(boolean isDone) {
-        this.isDone = isDone;
-    }
-
-    public boolean isDone() {
-        return isDone;
-    }
-
-    @Override
-    @NonNull
-    public String toString() {
-        return "TaskListItem{" +
-                "isDone=" + isDone +
-                '}';
-    }
-}
diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java
index a27aeb01..4847b196 100644
--- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java
+++ b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPlugin.java
@@ -9,12 +9,15 @@ import androidx.annotation.AttrRes;
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 
-import org.commonmark.parser.Parser;
+import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
+import com.vladsch.flexmark.ext.gfm.tasklist.TaskListItem;
+import com.vladsch.flexmark.parser.Parser;
+
+import java.util.Collections;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.MarkwonSpansFactory;
 import io.noties.markwon.MarkwonVisitor;
-import io.noties.markwon.core.SimpleBlockNodeVisitor;
 
 /**
  * @since 3.0.0
@@ -62,20 +65,19 @@ public class TaskListPlugin extends AbstractMarkwonPlugin {
         this.drawable = drawable;
     }
 
-    @Override
-    public void configureParser(@NonNull Parser.Builder builder) {
-        builder.postProcessor(new TaskListPostProcessor());
-    }
-
     @Override
     public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
         builder.setFactory(TaskListItem.class, new TaskListSpanFactory(drawable));
     }
 
+    @Override
+    public void configureParser(@NonNull Parser.Builder builder) {
+        builder.extensions(Collections.singleton(TaskListExtension.create()));
+    }
+
     @Override
     public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
-        builder
-                .on(TaskListItem.class, new MarkwonVisitor.NodeVisitor<TaskListItem>() {
+        builder.on(TaskListItem.class, new MarkwonVisitor.NodeVisitor<TaskListItem>() {
                     @Override
                     public void visit(@NonNull MarkwonVisitor visitor, @NonNull TaskListItem taskListItem) {
 
@@ -83,7 +85,7 @@ public class TaskListPlugin extends AbstractMarkwonPlugin {
 
                         visitor.visitChildren(taskListItem);
 
-                        TaskListProps.DONE.set(visitor.renderProps(), taskListItem.isDone());
+                        TaskListProps.DONE.set(visitor.renderProps(), taskListItem.isItemDoneMarker());
 
                         visitor.setSpansForNode(taskListItem, length);
 
diff --git a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPostProcessor.java b/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPostProcessor.java
deleted file mode 100644
index 7ea97244..00000000
--- a/markwon-ext-tasklist/src/main/java/io/noties/markwon/ext/tasklist/TaskListPostProcessor.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package io.noties.markwon.ext.tasklist;
-
-import android.text.TextUtils;
-
-import org.commonmark.node.AbstractVisitor;
-import org.commonmark.node.ListItem;
-import org.commonmark.node.Node;
-import org.commonmark.node.Paragraph;
-import org.commonmark.node.Text;
-import org.commonmark.parser.PostProcessor;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import io.noties.markwon.utils.ParserUtils;
-
-// @since 4.6.0
-// Hint taken from commonmark-ext-task-list-items artifact
-class TaskListPostProcessor implements PostProcessor {
-
-    @Override
-    public Node process(Node node) {
-        final TaskListVisitor visitor = new TaskListVisitor();
-        node.accept(visitor);
-        return node;
-    }
-
-    private static class TaskListVisitor extends AbstractVisitor {
-
-        private static final Pattern REGEX_TASK_LIST_ITEM = Pattern.compile("^\\[([xX\\s])]\\s+(.*)");
-
-        @Override
-        public void visit(ListItem listItem) {
-            // Takes first child and checks if it is Text (we are looking for exact `[xX\s]` without any formatting)
-            final Node child = listItem.getFirstChild();
-            // check if it is paragraph (can contain text)
-            if (child instanceof Paragraph) {
-                final Node node = child.getFirstChild();
-                if (node instanceof Text) {
-
-                    final Text textNode = (Text) node;
-                    final Matcher matcher = REGEX_TASK_LIST_ITEM.matcher(textNode.getLiteral());
-
-                    if (matcher.matches()) {
-                        final String checked = matcher.group(1);
-                        final boolean isChecked = "x".equals(checked) || "X".equals(checked);
-
-                        final TaskListItem taskListItem = new TaskListItem(isChecked);
-
-                        final Paragraph paragraph = new Paragraph();
-
-                        // insert before list item (directly before inside parent)
-                        listItem.insertBefore(taskListItem);
-
-                        // append the rest of matched text (can be empty)
-                        final String restMatchedText = matcher.group(2);
-                        if (!TextUtils.isEmpty(restMatchedText)) {
-                            paragraph.appendChild(new Text(restMatchedText));
-                        }
-
-                        // move all the rest children (from the first paragraph)
-                        ParserUtils.moveChildren(paragraph, node);
-
-                        // append our created paragraph
-                        taskListItem.appendChild(paragraph);
-
-                        // move all the rest children from the listItem (further nested lists, etc)
-                        ParserUtils.moveChildren(taskListItem, child);
-
-                        // remove list item from node
-                        listItem.unlink();
-
-                        // visit taskListItem children
-                        visitChildren(taskListItem);
-                        return;
-                    }
-                }
-            }
-            visitChildren(listItem);
-        }
-    }
-}
diff --git a/markwon-html/build.gradle b/markwon-html/build.gradle
index 4337e0d9..adcff6aa 100644
--- a/markwon-html/build.gradle
+++ b/markwon-html/build.gradle
@@ -22,7 +22,6 @@ dependencies {
         // we will try to obtain a SpanFactory for a Strikethrough node and use
         // it to be consistent with markdown (please note that we do not use markwon plugin
         // for that in case if different implementation is used)
-        compileOnly it['commonmark-strikethrough']
 
         testImplementation it['ix-java']
     }
@@ -34,3 +33,4 @@ dependencies {
 }
 
 registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java
index f2c2ea54..0d1f626a 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/HtmlPlugin.java
@@ -3,9 +3,9 @@ package io.noties.markwon.html;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.HtmlBlock;
-import org.commonmark.node.HtmlInline;
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.ast.HtmlBlock;
+import com.vladsch.flexmark.ast.HtmlInline;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.MarkwonConfiguration;
@@ -161,13 +161,13 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
                 .on(HtmlBlock.class, new MarkwonVisitor.NodeVisitor<HtmlBlock>() {
                     @Override
                     public void visit(@NonNull MarkwonVisitor visitor, @NonNull HtmlBlock htmlBlock) {
-                        visitHtml(visitor, htmlBlock.getLiteral());
+                        visitHtml(visitor, htmlBlock.toAstString(false));
                     }
                 })
                 .on(HtmlInline.class, new MarkwonVisitor.NodeVisitor<HtmlInline>() {
                     @Override
                     public void visit(@NonNull MarkwonVisitor visitor, @NonNull HtmlInline htmlInline) {
-                        visitHtml(visitor, htmlInline.getLiteral());
+                        visitHtml(visitor, htmlInline.toAstString(false));
                     }
                 });
     }
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java
index 353f6d9b..ae5db174 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/jsoup/nodes/CommonMarkEntities.java
@@ -2,7 +2,7 @@ package io.noties.markwon.html.jsoup.nodes;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.internal.util.Html5Entities;
+import com.vladsch.flexmark.util.sequence.Html5Entities;
 
 import java.lang.reflect.Field;
 import java.util.Collections;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java
index e579a7d3..3c44656f 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/BlockquoteHandler.java
@@ -2,7 +2,7 @@ package io.noties.markwon.html.tag;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.BlockQuote;
+import com.vladsch.flexmark.ast.BlockQuote;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java
index d1f7fdd8..672c9ff2 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/EmphasisHandler.java
@@ -3,7 +3,7 @@ package io.noties.markwon.html.tag;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Emphasis;
+import com.vladsch.flexmark.ast.Emphasis;
 
 import java.util.Arrays;
 import java.util.Collection;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java
index 7c694e2d..c46b2bb1 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/HeadingHandler.java
@@ -3,7 +3,7 @@ package io.noties.markwon.html.tag;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Heading;
+import com.vladsch.flexmark.ast.Heading;
 
 import java.util.Arrays;
 import java.util.Collection;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java
index 833c4926..4563c92e 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ImageHandler.java
@@ -5,7 +5,7 @@ import android.text.TextUtils;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Image;
+import com.vladsch.flexmark.ast.Image;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java
index d5e032f7..e09f066f 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/LinkHandler.java
@@ -5,7 +5,7 @@ import android.text.TextUtils;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Link;
+import com.vladsch.flexmark.ast.Link;
 
 import java.util.Collection;
 import java.util.Collections;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java
index 33499b6c..d8e362c3 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/ListHandler.java
@@ -2,7 +2,7 @@ package io.noties.markwon.html.tag;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.ListItem;
+import com.vladsch.flexmark.ast.ListItem;
 
 import java.util.Arrays;
 import java.util.Collection;
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java
index 03a0e952..d594c5da 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrikeHandler.java
@@ -5,6 +5,8 @@ import android.text.style.StrikethroughSpan;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.vladsch.flexmark.ext.gfm.strikethrough.Strikethrough;
+
 import java.util.Arrays;
 import java.util.Collection;
 
@@ -63,7 +65,7 @@ public class StrikeHandler extends TagHandler {
     private static Object getMarkdownSpans(@NonNull MarkwonVisitor visitor) {
         final MarkwonConfiguration configuration = visitor.configuration();
         final SpanFactory spanFactory = configuration.spansFactory()
-                .get(org.commonmark.ext.gfm.strikethrough.Strikethrough.class);
+                .get(Strikethrough.class);
         if (spanFactory == null) {
             return null;
         }
diff --git a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java
index a698ae44..84386dca 100644
--- a/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java
+++ b/markwon-html/src/main/java/io/noties/markwon/html/tag/StrongEmphasisHandler.java
@@ -3,7 +3,7 @@ package io.noties.markwon.html.tag;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.StrongEmphasis;
+import com.vladsch.flexmark.ast.StrongEmphasis;
 
 import java.util.Arrays;
 import java.util.Collection;
diff --git a/markwon-image-coil/build.gradle b/markwon-image-coil/build.gradle
index 26fe01ea..911af7bf 100644
--- a/markwon-image-coil/build.gradle
+++ b/markwon-image-coil/build.gradle
@@ -23,3 +23,4 @@ dependencies {
 }
 
 registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-image-coil/src/main/java/io/noties/markwon/image/coil/CoilImagesPlugin.java b/markwon-image-coil/src/main/java/io/noties/markwon/image/coil/CoilImagesPlugin.java
index 605e5146..af4ce8eb 100644
--- a/markwon-image-coil/src/main/java/io/noties/markwon/image/coil/CoilImagesPlugin.java
+++ b/markwon-image-coil/src/main/java/io/noties/markwon/image/coil/CoilImagesPlugin.java
@@ -8,7 +8,7 @@ import android.widget.TextView;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import org.commonmark.node.Image;
+import com.vladsch.flexmark.ast.Image;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/markwon-image-glide/build.gradle b/markwon-image-glide/build.gradle
index a9d3ef66..0b185ec5 100644
--- a/markwon-image-glide/build.gradle
+++ b/markwon-image-glide/build.gradle
@@ -18,4 +18,5 @@ dependencies {
     api deps['glide']
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java
index c48df4af..93be5d88 100644
--- a/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java
+++ b/markwon-image-glide/src/main/java/io/noties/markwon/image/glide/GlideImagesPlugin.java
@@ -14,8 +14,7 @@ import com.bumptech.glide.RequestManager;
 import com.bumptech.glide.request.target.CustomTarget;
 import com.bumptech.glide.request.target.Target;
 import com.bumptech.glide.request.transition.Transition;
-
-import org.commonmark.node.Image;
+import com.vladsch.flexmark.ast.Image;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/markwon-image-picasso/build.gradle b/markwon-image-picasso/build.gradle
index b646c01c..07c07fa4 100644
--- a/markwon-image-picasso/build.gradle
+++ b/markwon-image-picasso/build.gradle
@@ -18,4 +18,5 @@ dependencies {
     api deps['picasso']
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java
index ea751030..99c88660 100644
--- a/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java
+++ b/markwon-image-picasso/src/main/java/io/noties/markwon/image/picasso/PicassoImagesPlugin.java
@@ -14,8 +14,7 @@ import androidx.annotation.Nullable;
 import com.squareup.picasso.Picasso;
 import com.squareup.picasso.RequestCreator;
 import com.squareup.picasso.Target;
-
-import org.commonmark.node.Image;
+import com.vladsch.flexmark.ast.Image;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/markwon-image/build.gradle b/markwon-image/build.gradle
index 9953b415..dfdd3a97 100644
--- a/markwon-image/build.gradle
+++ b/markwon-image/build.gradle
@@ -34,4 +34,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java
index bd653369..eecfd612 100644
--- a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java
+++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java
@@ -8,7 +8,7 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.commonmark.node.Image;
+import com.vladsch.flexmark.ast.Image;
 
 import java.util.concurrent.ExecutorService;
 
diff --git a/markwon-inline-parser/README.md b/markwon-inline-parser/README.md
deleted file mode 100644
index bcfa3802..00000000
--- a/markwon-inline-parser/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Inline parser
-
-**Experimental** due to usage of internal (but still visible) classes of commonmark-java:
-
-```java
-import org.commonmark.internal.Bracket;
-import org.commonmark.internal.Delimiter;
-import org.commonmark.internal.ReferenceParser;
-import org.commonmark.internal.util.Escaping;
-import org.commonmark.internal.util.Html5Entities;
-import org.commonmark.internal.util.Parsing;
-import org.commonmark.internal.inline.AsteriskDelimiterProcessor;
-import org.commonmark.internal.inline.UnderscoreDelimiterProcessor;
-```
-
-`StaggeredDelimiterProcessor` class source is copied (required for InlineParser)
\ No newline at end of file
diff --git a/markwon-inline-parser/build.gradle b/markwon-inline-parser/build.gradle
deleted file mode 100644
index 32a45d7c..00000000
--- a/markwon-inline-parser/build.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-apply plugin: 'com.android.library'
-
-android {
-
-    compileSdkVersion config['compile-sdk']
-    buildToolsVersion config['build-tools']
-
-    defaultConfig {
-        minSdkVersion config['min-sdk']
-        targetSdkVersion config['target-sdk']
-        versionCode 1
-        versionName version
-    }
-}
-
-dependencies {
-    api project(':markwon-core')
-    api deps['x-annotations']
-    api deps['commonmark']
-
-    deps['test'].with {
-        testImplementation it['junit']
-        testImplementation it['commonmark-test-util']
-    }
-}
-
-registerArtifact(this)
\ No newline at end of file
diff --git a/markwon-inline-parser/gradle.properties b/markwon-inline-parser/gradle.properties
deleted file mode 100644
index 264a18ee..00000000
--- a/markwon-inline-parser/gradle.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-POM_NAME=Inline Parser
-POM_ARTIFACT_ID=inline-parser
-POM_DESCRIPTION=Markwon customizable commonmark-java InlineParser
-POM_PACKAGING=aar
\ No newline at end of file
diff --git a/markwon-inline-parser/src/main/AndroidManifest.xml b/markwon-inline-parser/src/main/AndroidManifest.xml
deleted file mode 100644
index 1a8bcbb5..00000000
--- a/markwon-inline-parser/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1 +0,0 @@
-<manifest package="io.noties.markwon.inlineparser" />
\ No newline at end of file
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AutolinkInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AutolinkInlineProcessor.java
deleted file mode 100644
index cbba2763..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/AutolinkInlineProcessor.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.node.Link;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-import java.util.regex.Pattern;
-
-/**
- * Parses autolinks, for example {@code <me@mydoma.in>}
- *
- * @since 4.2.0
- */
-public class AutolinkInlineProcessor extends InlineProcessor {
-
-    private static final Pattern EMAIL_AUTOLINK = Pattern
-            .compile("^<([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>");
-
-    private static final Pattern AUTOLINK = Pattern
-            .compile("^<[a-zA-Z][a-zA-Z0-9.+-]{1,31}:[^<>\u0000-\u0020]*>");
-
-    @Override
-    public char specialCharacter() {
-        return '<';
-    }
-
-    @Override
-    protected Node parse() {
-        String m;
-        if ((m = match(EMAIL_AUTOLINK)) != null) {
-            String dest = m.substring(1, m.length() - 1);
-            Link node = new Link("mailto:" + dest, null);
-            node.appendChild(new Text(dest));
-            return node;
-        } else if ((m = match(AUTOLINK)) != null) {
-            String dest = m.substring(1, m.length() - 1);
-            Link node = new Link(dest, null);
-            node.appendChild(new Text(dest));
-            return node;
-        } else {
-            return null;
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackslashInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackslashInlineProcessor.java
deleted file mode 100644
index c4afc3e0..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackslashInlineProcessor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.node.HardLineBreak;
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-/**
- * @since 4.2.0
- */
-public class BackslashInlineProcessor extends InlineProcessor {
-
-    private static final Pattern ESCAPABLE = MarkwonInlineParser.ESCAPABLE;
-
-    @Override
-    public char specialCharacter() {
-        return '\\';
-    }
-
-    @Override
-    protected Node parse() {
-        index++;
-        Node node;
-        if (peek() == '\n') {
-            node = new HardLineBreak();
-            index++;
-        } else if (index < input.length() && ESCAPABLE.matcher(input.substring(index, index + 1)).matches()) {
-            node = text(input, index, index + 1);
-            index++;
-        } else {
-            node = text("\\");
-        }
-        return node;
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackticksInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackticksInlineProcessor.java
deleted file mode 100644
index ef5be678..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BackticksInlineProcessor.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.internal.util.Parsing;
-import org.commonmark.node.Code;
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-/**
- * Parses inline code surrounded with {@code `} chars {@code `code`}
- *
- * @since 4.2.0
- */
-public class BackticksInlineProcessor extends InlineProcessor {
-
-    private static final Pattern TICKS = Pattern.compile("`+");
-
-    private static final Pattern TICKS_HERE = Pattern.compile("^`+");
-
-    @Override
-    public char specialCharacter() {
-        return '`';
-    }
-
-    @Override
-    protected Node parse() {
-        String ticks = match(TICKS_HERE);
-        if (ticks == null) {
-            return null;
-        }
-        int afterOpenTicks = index;
-        String matched;
-        while ((matched = match(TICKS)) != null) {
-            if (matched.equals(ticks)) {
-                Code node = new Code();
-                String content = input.substring(afterOpenTicks, index - ticks.length());
-                content = content.replace('\n', ' ');
-
-                // spec: If the resulting string both begins and ends with a space character, but does not consist
-                // entirely of space characters, a single space character is removed from the front and back.
-                if (content.length() >= 3 &&
-                        content.charAt(0) == ' ' &&
-                        content.charAt(content.length() - 1) == ' ' &&
-                        Parsing.hasNonSpace(content)) {
-                    content = content.substring(1, content.length() - 1);
-                }
-
-                node.setLiteral(content);
-                return node;
-            }
-        }
-        // If we got here, we didn't match a closing backtick sequence.
-        index = afterOpenTicks;
-        return text(ticks);
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BangInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BangInlineProcessor.java
deleted file mode 100644
index eb96c1e9..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/BangInlineProcessor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.internal.Bracket;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-/**
- * Parses markdown images {@code ![alt](#href)}
- *
- * @since 4.2.0
- */
-public class BangInlineProcessor extends InlineProcessor {
-    @Override
-    public char specialCharacter() {
-        return '!';
-    }
-
-    @Override
-    protected Node parse() {
-        int startIndex = index;
-        index++;
-        if (peek() == '[') {
-            index++;
-
-            Text node = text("![");
-
-            // Add entry to stack for this opener
-            addBracket(Bracket.image(node, startIndex + 1, lastBracket(), lastDelimiter()));
-
-            return node;
-        } else {
-            return null;
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/CloseBracketInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/CloseBracketInlineProcessor.java
deleted file mode 100644
index b9d2f867..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/CloseBracketInlineProcessor.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.internal.Bracket;
-import org.commonmark.internal.util.Escaping;
-import org.commonmark.node.Image;
-import org.commonmark.node.Link;
-import org.commonmark.node.LinkReferenceDefinition;
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-import static io.noties.markwon.inlineparser.InlineParserUtils.mergeChildTextNodes;
-
-/**
- * Parses markdown link or image, relies on {@link OpenBracketInlineProcessor}
- * to handle start of these elements
- *
- * @since 4.2.0
- */
-public class CloseBracketInlineProcessor extends InlineProcessor {
-
-    private static final Pattern WHITESPACE = MarkwonInlineParser.WHITESPACE;
-
-    @Override
-    public char specialCharacter() {
-        return ']';
-    }
-
-    @Override
-    protected Node parse() {
-        index++;
-        int startIndex = index;
-
-        // Get previous `[` or `![`
-        Bracket opener = lastBracket();
-        if (opener == null) {
-            // No matching opener, just return a literal.
-            return text("]");
-        }
-
-        if (!opener.allowed) {
-            // Matching opener but it's not allowed, just return a literal.
-            removeLastBracket();
-            return text("]");
-        }
-
-        // Check to see if we have a link/image
-
-        String dest = null;
-        String title = null;
-        boolean isLinkOrImage = false;
-
-        // Maybe a inline link like `[foo](/uri "title")`
-        if (peek() == '(') {
-            index++;
-            spnl();
-            if ((dest = parseLinkDestination()) != null) {
-                spnl();
-                // title needs a whitespace before
-                if (WHITESPACE.matcher(input.substring(index - 1, index)).matches()) {
-                    title = parseLinkTitle();
-                    spnl();
-                }
-                if (peek() == ')') {
-                    index++;
-                    isLinkOrImage = true;
-                } else {
-                    index = startIndex;
-                }
-            }
-        }
-
-        // Maybe a reference link like `[foo][bar]`, `[foo][]` or `[foo]`
-        if (!isLinkOrImage) {
-
-            // See if there's a link label like `[bar]` or `[]`
-            int beforeLabel = index;
-            parseLinkLabel();
-            int labelLength = index - beforeLabel;
-            String ref = null;
-            if (labelLength > 2) {
-                ref = input.substring(beforeLabel, beforeLabel + labelLength);
-            } else if (!opener.bracketAfter) {
-                // If the second label is empty `[foo][]` or missing `[foo]`, then the first label is the reference.
-                // But it can only be a reference when there's no (unescaped) bracket in it.
-                // If there is, we don't even need to try to look up the reference. This is an optimization.
-                ref = input.substring(opener.index, startIndex);
-            }
-
-            if (ref != null) {
-                String label = Escaping.normalizeReference(ref);
-                LinkReferenceDefinition definition = context.getLinkReferenceDefinition(label);
-                if (definition != null) {
-                    dest = definition.getDestination();
-                    title = definition.getTitle();
-                    isLinkOrImage = true;
-                }
-            }
-        }
-
-        if (isLinkOrImage) {
-            // If we got here, open is a potential opener
-            Node linkOrImage = opener.image ? new Image(dest, title) : new Link(dest, title);
-
-            Node node = opener.node.getNext();
-            while (node != null) {
-                Node next = node.getNext();
-                linkOrImage.appendChild(node);
-                node = next;
-            }
-
-            // Process delimiters such as emphasis inside link/image
-            processDelimiters(opener.previousDelimiter);
-            mergeChildTextNodes(linkOrImage);
-            // We don't need the corresponding text node anymore, we turned it into a link/image node
-            opener.node.unlink();
-            removeLastBracket();
-
-            // Links within links are not allowed. We found this link, so there can be no other link around it.
-            if (!opener.image) {
-                Bracket bracket = lastBracket();
-                while (bracket != null) {
-                    if (!bracket.image) {
-                        // Disallow link opener. It will still get matched, but will not result in a link.
-                        bracket.allowed = false;
-                    }
-                    bracket = bracket.previous;
-                }
-            }
-
-            return linkOrImage;
-
-        } else { // no link or image
-            index = startIndex;
-            removeLastBracket();
-
-            return text("]");
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/EntityInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/EntityInlineProcessor.java
deleted file mode 100644
index 353f9902..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/EntityInlineProcessor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.internal.util.Escaping;
-import org.commonmark.internal.util.Html5Entities;
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-/**
- * Parses HTML entities {@code &amp;}
- *
- * @since 4.2.0
- */
-public class EntityInlineProcessor extends InlineProcessor {
-
-    private static final Pattern ENTITY_HERE = Pattern.compile('^' + Escaping.ENTITY, Pattern.CASE_INSENSITIVE);
-
-    @Override
-    public char specialCharacter() {
-        return '&';
-    }
-
-    @Override
-    protected Node parse() {
-        String m;
-        if ((m = match(ENTITY_HERE)) != null) {
-            return text(Html5Entities.entityToString(m));
-        } else {
-            return null;
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/HtmlInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/HtmlInlineProcessor.java
deleted file mode 100644
index d3bd579d..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/HtmlInlineProcessor.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.internal.util.Parsing;
-import org.commonmark.node.HtmlInline;
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-/**
- * Parses inline HTML tags
- *
- * @since 4.2.0
- */
-public class HtmlInlineProcessor extends InlineProcessor {
-
-    private static final String HTMLCOMMENT = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->";
-    private static final String PROCESSINGINSTRUCTION = "[<][?].*?[?][>]";
-    private static final String DECLARATION = "<![A-Z]+\\s+[^>]*>";
-    private static final String CDATA = "<!\\[CDATA\\[[\\s\\S]*?\\]\\]>";
-    private static final String HTMLTAG = "(?:" + Parsing.OPENTAG + "|" + Parsing.CLOSETAG + "|" + HTMLCOMMENT
-            + "|" + PROCESSINGINSTRUCTION + "|" + DECLARATION + "|" + CDATA + ")";
-    private static final Pattern HTML_TAG = Pattern.compile('^' + HTMLTAG, Pattern.CASE_INSENSITIVE);
-
-    @Override
-    public char specialCharacter() {
-        return '<';
-    }
-
-    @Override
-    protected Node parse() {
-        String m = match(HTML_TAG);
-        if (m != null) {
-            HtmlInline node = new HtmlInline();
-            node.setLiteral(m);
-            return node;
-        } else {
-            return null;
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineParserUtils.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineParserUtils.java
deleted file mode 100644
index 1ffb9131..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineParserUtils.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-/**
- * @since 4.2.0
- */
-public abstract class InlineParserUtils {
-
-    public static void mergeTextNodesBetweenExclusive(Node fromNode, Node toNode) {
-        // No nodes between them
-        if (fromNode == toNode || fromNode.getNext() == toNode) {
-            return;
-        }
-
-        mergeTextNodesInclusive(fromNode.getNext(), toNode.getPrevious());
-    }
-
-    public static void mergeChildTextNodes(Node node) {
-        // No children or just one child node, no need for merging
-        if (node.getFirstChild() == node.getLastChild()) {
-            return;
-        }
-
-        mergeTextNodesInclusive(node.getFirstChild(), node.getLastChild());
-    }
-
-    public static void mergeTextNodesInclusive(Node fromNode, Node toNode) {
-        Text first = null;
-        Text last = null;
-        int length = 0;
-
-        Node node = fromNode;
-        while (node != null) {
-            if (node instanceof Text) {
-                Text text = (Text) node;
-                if (first == null) {
-                    first = text;
-                }
-                length += text.getLiteral().length();
-                last = text;
-            } else {
-                mergeIfNeeded(first, last, length);
-                first = null;
-                last = null;
-                length = 0;
-            }
-            if (node == toNode) {
-                break;
-            }
-            node = node.getNext();
-        }
-
-        mergeIfNeeded(first, last, length);
-    }
-
-    public static void mergeIfNeeded(Text first, Text last, int textLength) {
-        if (first != null && last != null && first != last) {
-            StringBuilder sb = new StringBuilder(textLength);
-            sb.append(first.getLiteral());
-            Node node = first.getNext();
-            Node stop = last.getNext();
-            while (node != stop) {
-                sb.append(((Text) node).getLiteral());
-                Node unlink = node;
-                node = node.getNext();
-                unlink.unlink();
-            }
-            String literal = sb.toString();
-            first.setLiteral(literal);
-        }
-    }
-
-    private InlineParserUtils() {
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineProcessor.java
deleted file mode 100644
index b7917578..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/InlineProcessor.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.commonmark.internal.Bracket;
-import org.commonmark.internal.Delimiter;
-import org.commonmark.node.Link;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-import java.util.Map;
-import java.util.regex.Pattern;
-
-/**
- * @see AutolinkInlineProcessor
- * @see BackslashInlineProcessor
- * @see BackticksInlineProcessor
- * @see BangInlineProcessor
- * @see CloseBracketInlineProcessor
- * @see EntityInlineProcessor
- * @see HtmlInlineProcessor
- * @see NewLineInlineProcessor
- * @see OpenBracketInlineProcessor
- * @see MarkwonInlineParser.FactoryBuilder#addInlineProcessor(InlineProcessor)
- * @see MarkwonInlineParser.FactoryBuilder#excludeInlineProcessor(Class)
- * @since 4.2.0
- */
-public abstract class InlineProcessor {
-
-    /**
-     * Special character that triggers parsing attempt
-     */
-    public abstract char specialCharacter();
-
-    /**
-     * @return boolean indicating if parsing succeeded
-     */
-    @Nullable
-    protected abstract Node parse();
-
-
-    protected MarkwonInlineParserContext context;
-    protected Node block;
-    protected String input;
-    protected int index;
-
-    @Nullable
-    public Node parse(@NonNull MarkwonInlineParserContext context) {
-        this.context = context;
-        this.block = context.block();
-        this.input = context.input();
-        this.index = context.index();
-
-        final Node result = parse();
-
-        // synchronize index
-        context.setIndex(index);
-
-        return result;
-    }
-
-    protected Bracket lastBracket() {
-        return context.lastBracket();
-    }
-
-    protected Delimiter lastDelimiter() {
-        return context.lastDelimiter();
-    }
-
-    protected void addBracket(Bracket bracket) {
-        context.addBracket(bracket);
-    }
-
-    protected void removeLastBracket() {
-        context.removeLastBracket();
-    }
-
-    protected void spnl() {
-        context.setIndex(index);
-        context.spnl();
-        index = context.index();
-    }
-
-    @Nullable
-    protected String match(@NonNull Pattern re) {
-        // before trying to match, we must notify context about our index (which we store additionally here)
-        context.setIndex(index);
-
-        final String result = context.match(re);
-
-        // after match we must reflect index change here
-        this.index = context.index();
-
-        return result;
-    }
-
-    @Nullable
-    protected String parseLinkDestination() {
-        context.setIndex(index);
-        final String result = context.parseLinkDestination();
-        this.index = context.index();
-        return result;
-    }
-
-    @Nullable
-    protected String parseLinkTitle() {
-        context.setIndex(index);
-        final String result = context.parseLinkTitle();
-        this.index = context.index();
-        return result;
-    }
-
-    protected int parseLinkLabel() {
-        context.setIndex(index);
-        final int result = context.parseLinkLabel();
-        this.index = context.index();
-        return result;
-    }
-
-    protected void processDelimiters(Delimiter stackBottom) {
-        context.setIndex(index);
-        context.processDelimiters(stackBottom);
-        this.index = context.index();
-    }
-
-    @NonNull
-    protected Text text(@NonNull String text) {
-        return context.text(text);
-    }
-
-    @NonNull
-    protected Text text(@NonNull String text, int start, int end) {
-        return context.text(text, start, end);
-    }
-
-    protected char peek() {
-        context.setIndex(index);
-        return context.peek();
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java
deleted file mode 100644
index 14c24597..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParser.java
+++ /dev/null
@@ -1,831 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.commonmark.internal.Bracket;
-import org.commonmark.internal.Delimiter;
-import org.commonmark.internal.inline.AsteriskDelimiterProcessor;
-import org.commonmark.internal.inline.UnderscoreDelimiterProcessor;
-import org.commonmark.internal.util.Escaping;
-import org.commonmark.internal.util.LinkScanner;
-import org.commonmark.node.LinkReferenceDefinition;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-import org.commonmark.parser.InlineParser;
-import org.commonmark.parser.InlineParserContext;
-import org.commonmark.parser.InlineParserFactory;
-import org.commonmark.parser.delimiter.DelimiterProcessor;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static io.noties.markwon.inlineparser.InlineParserUtils.mergeChildTextNodes;
-import static io.noties.markwon.inlineparser.InlineParserUtils.mergeTextNodesBetweenExclusive;
-
-/**
- * @see #factoryBuilder()
- * @see #factoryBuilderNoDefaults()
- * @see FactoryBuilder
- * @since 4.2.0
- */
-public class MarkwonInlineParser implements InlineParser, MarkwonInlineParserContext {
-
-    @SuppressWarnings("unused")
-    public interface FactoryBuilder {
-
-        /**
-         * @see InlineProcessor
-         */
-        @NonNull
-        FactoryBuilder addInlineProcessor(@NonNull InlineProcessor processor);
-
-        /**
-         * @see AsteriskDelimiterProcessor
-         * @see UnderscoreDelimiterProcessor
-         */
-        @NonNull
-        FactoryBuilder addDelimiterProcessor(@NonNull DelimiterProcessor processor);
-
-        /**
-         * Indicate if markdown references are enabled. By default = `true`
-         */
-        @NonNull
-        FactoryBuilder referencesEnabled(boolean referencesEnabled);
-
-        @NonNull
-        FactoryBuilder excludeInlineProcessor(@NonNull Class<? extends InlineProcessor> processor);
-
-        @NonNull
-        FactoryBuilder excludeDelimiterProcessor(@NonNull Class<? extends DelimiterProcessor> processor);
-
-        @NonNull
-        InlineParserFactory build();
-    }
-
-    public interface FactoryBuilderNoDefaults extends FactoryBuilder {
-        /**
-         * Includes all default delimiter and inline processors, and sets {@code referencesEnabled=true}.
-         * Useful with subsequent calls to {@link #excludeInlineProcessor(Class)} or {@link #excludeDelimiterProcessor(Class)}
-         */
-        @NonNull
-        FactoryBuilder includeDefaults();
-    }
-
-    /**
-     * Creates an instance of {@link FactoryBuilder} and includes all defaults.
-     *
-     * @see #factoryBuilderNoDefaults()
-     */
-    @NonNull
-    public static FactoryBuilder factoryBuilder() {
-        return new FactoryBuilderImpl().includeDefaults();
-    }
-
-    /**
-     * NB, this return an <em>empty</em> builder, so if no {@link FactoryBuilderNoDefaults#includeDefaults()}
-     * is called, it means effectively <strong>no inline parsing</strong> (unless further calls
-     * to {@link FactoryBuilder#addInlineProcessor(InlineProcessor)} or {@link FactoryBuilder#addDelimiterProcessor(DelimiterProcessor)}).
-     */
-    @NonNull
-    public static FactoryBuilderNoDefaults factoryBuilderNoDefaults() {
-        return new FactoryBuilderImpl();
-    }
-
-    private static final String ASCII_PUNCTUATION = "!\"#\\$%&'\\(\\)\\*\\+,\\-\\./:;<=>\\?@\\[\\\\\\]\\^_`\\{\\|\\}~";
-    private static final Pattern PUNCTUATION = Pattern
-            .compile("^[" + ASCII_PUNCTUATION + "\\p{Pc}\\p{Pd}\\p{Pe}\\p{Pf}\\p{Pi}\\p{Po}\\p{Ps}]");
-
-    private static final Pattern SPNL = Pattern.compile("^ *(?:\n *)?");
-
-    private static final Pattern UNICODE_WHITESPACE_CHAR = Pattern.compile("^[\\p{Zs}\t\r\n\f]");
-
-    static final Pattern ESCAPABLE = Pattern.compile('^' + Escaping.ESCAPABLE);
-    static final Pattern WHITESPACE = Pattern.compile("\\s+");
-
-    private final InlineParserContext inlineParserContext;
-
-    private final boolean referencesEnabled;
-
-    private final BitSet specialCharacters;
-    private final Map<Character, List<InlineProcessor>> inlineProcessors;
-    private final Map<Character, DelimiterProcessor> delimiterProcessors;
-
-    // currently we still hold a reference to it because we decided not to
-    //  pass previous node argument to inline-processors (current usage is limited with NewLineInlineProcessor)
-    private Node block;
-    private String input;
-    private int index;
-
-    /**
-     * Top delimiter (emphasis, strong emphasis or custom emphasis). (Brackets are on a separate stack, different
-     * from the algorithm described in the spec.)
-     */
-    private Delimiter lastDelimiter;
-
-    /**
-     * Top opening bracket (<code>[</code> or <code>![)</code>).
-     */
-    private Bracket lastBracket;
-
-    // might we construct these in factory?
-    public MarkwonInlineParser(
-            @NonNull InlineParserContext inlineParserContext,
-            boolean referencesEnabled,
-            @NonNull List<InlineProcessor> inlineProcessors,
-            @NonNull List<DelimiterProcessor> delimiterProcessors) {
-        this.inlineParserContext = inlineParserContext;
-        this.referencesEnabled = referencesEnabled;
-        this.inlineProcessors = calculateInlines(inlineProcessors);
-        this.delimiterProcessors = calculateDelimiterProcessors(delimiterProcessors);
-        this.specialCharacters = calculateSpecialCharacters(
-                this.inlineProcessors.keySet(),
-                this.delimiterProcessors.keySet());
-    }
-
-    @NonNull
-    private static Map<Character, List<InlineProcessor>> calculateInlines(@NonNull List<InlineProcessor> inlines) {
-        final Map<Character, List<InlineProcessor>> map = new HashMap<>(inlines.size());
-        List<InlineProcessor> list;
-        for (InlineProcessor inlineProcessor : inlines) {
-            final char character = inlineProcessor.specialCharacter();
-            list = map.get(character);
-            if (list == null) {
-                list = new ArrayList<>(1);
-                map.put(character, list);
-            }
-            list.add(inlineProcessor);
-        }
-        return map;
-    }
-
-    @NonNull
-    private static BitSet calculateSpecialCharacters(Set<Character> inlineCharacters, Set<Character> delimiterCharacters) {
-        final BitSet bitSet = new BitSet();
-        for (Character c : inlineCharacters) {
-            bitSet.set(c);
-        }
-        for (Character c : delimiterCharacters) {
-            bitSet.set(c);
-        }
-        return bitSet;
-    }
-
-    private static Map<Character, DelimiterProcessor> calculateDelimiterProcessors(List<DelimiterProcessor> delimiterProcessors) {
-        Map<Character, DelimiterProcessor> map = new HashMap<>();
-        addDelimiterProcessors(delimiterProcessors, map);
-        return map;
-    }
-
-    private static void addDelimiterProcessors(Iterable<DelimiterProcessor> delimiterProcessors, Map<Character, DelimiterProcessor> map) {
-        for (DelimiterProcessor delimiterProcessor : delimiterProcessors) {
-            char opening = delimiterProcessor.getOpeningCharacter();
-            char closing = delimiterProcessor.getClosingCharacter();
-            if (opening == closing) {
-                DelimiterProcessor old = map.get(opening);
-                if (old != null && old.getOpeningCharacter() == old.getClosingCharacter()) {
-                    StaggeredDelimiterProcessor s;
-                    if (old instanceof StaggeredDelimiterProcessor) {
-                        s = (StaggeredDelimiterProcessor) old;
-                    } else {
-                        s = new StaggeredDelimiterProcessor(opening);
-                        s.add(old);
-                    }
-                    s.add(delimiterProcessor);
-                    map.put(opening, s);
-                } else {
-                    addDelimiterProcessorForChar(opening, delimiterProcessor, map);
-                }
-            } else {
-                addDelimiterProcessorForChar(opening, delimiterProcessor, map);
-                addDelimiterProcessorForChar(closing, delimiterProcessor, map);
-            }
-        }
-    }
-
-    private static void addDelimiterProcessorForChar(char delimiterChar, DelimiterProcessor toAdd, Map<Character, DelimiterProcessor> delimiterProcessors) {
-        DelimiterProcessor existing = delimiterProcessors.put(delimiterChar, toAdd);
-        if (existing != null) {
-            throw new IllegalArgumentException("Delimiter processor conflict with delimiter char '" + delimiterChar + "'");
-        }
-    }
-
-    /**
-     * Parse content in block into inline children, using reference map to resolve references.
-     */
-    @Override
-    public void parse(String content, Node block) {
-        reset(content.trim());
-
-        // we still reference it
-        this.block = block;
-
-        while (true) {
-            Node node = parseInline();
-            if (node != null) {
-                block.appendChild(node);
-            } else {
-                break;
-            }
-        }
-
-        processDelimiters(null);
-        mergeChildTextNodes(block);
-    }
-
-    private void reset(String content) {
-        this.input = content;
-        this.index = 0;
-        this.lastDelimiter = null;
-        this.lastBracket = null;
-    }
-
-    /**
-     * Parse the next inline element in subject, advancing input index.
-     * On success, add the result to block's children and return true.
-     * On failure, return false.
-     */
-    @Nullable
-    private Node parseInline() {
-
-        final char c = peek();
-
-        if (c == '\0') {
-            return null;
-        }
-
-        Node node = null;
-
-        final List<InlineProcessor> inlines = this.inlineProcessors.get(c);
-
-        if (inlines != null) {
-            // @since 4.6.0 index must not be advanced if inline-processor returned null
-            //  so, further processors can be called at the _same_ position (and thus char)
-            final int startIndex = index;
-
-            for (InlineProcessor inline : inlines) {
-                node = inline.parse(this);
-                if (node != null) {
-                    break;
-                }
-
-                // reset after each iteration (happens only when node is null)
-                index = startIndex;
-            }
-        } else {
-            final DelimiterProcessor delimiterProcessor = delimiterProcessors.get(c);
-            if (delimiterProcessor != null) {
-                node = parseDelimiters(delimiterProcessor, c);
-            } else {
-                node = parseString();
-            }
-        }
-
-        if (node != null) {
-            return node;
-        } else {
-            index++;
-            // When we get here, it's only for a single special character that turned out to not have a special meaning.
-            // So we shouldn't have a single surrogate here, hence it should be ok to turn it into a String.
-            String literal = String.valueOf(c);
-            return text(literal);
-        }
-    }
-
-    /**
-     * If RE matches at current index in the input, advance index and return the match; otherwise return null.
-     */
-    @Override
-    @Nullable
-    public String match(@NonNull Pattern re) {
-        if (index >= input.length()) {
-            return null;
-        }
-        Matcher matcher = re.matcher(input);
-        matcher.region(index, input.length());
-        boolean m = matcher.find();
-        if (m) {
-            index = matcher.end();
-            return matcher.group();
-        } else {
-            return null;
-        }
-    }
-
-    @NonNull
-    @Override
-    public Text text(@NonNull String text) {
-        return new Text(text);
-    }
-
-    @NonNull
-    @Override
-    public Text text(@NonNull String text, int beginIndex, int endIndex) {
-        return new Text(text.substring(beginIndex, endIndex));
-    }
-
-    @Nullable
-    @Override
-    public LinkReferenceDefinition getLinkReferenceDefinition(String label) {
-        return referencesEnabled
-                ? inlineParserContext.getLinkReferenceDefinition(label)
-                : null;
-    }
-
-    /**
-     * Returns the char at the current input index, or {@code '\0'} in case there are no more characters.
-     */
-    @Override
-    public char peek() {
-        if (index < input.length()) {
-            return input.charAt(index);
-        } else {
-            return '\0';
-        }
-    }
-
-    @NonNull
-    @Override
-    public Node block() {
-        return block;
-    }
-
-    @NonNull
-    @Override
-    public String input() {
-        return input;
-    }
-
-    @Override
-    public int index() {
-        return index;
-    }
-
-    @Override
-    public void setIndex(int index) {
-        this.index = index;
-    }
-
-    @Override
-    public Bracket lastBracket() {
-        return lastBracket;
-    }
-
-    @Override
-    public Delimiter lastDelimiter() {
-        return lastDelimiter;
-    }
-
-    @Override
-    public void addBracket(Bracket bracket) {
-        if (lastBracket != null) {
-            lastBracket.bracketAfter = true;
-        }
-        lastBracket = bracket;
-    }
-
-    @Override
-    public void removeLastBracket() {
-        lastBracket = lastBracket.previous;
-    }
-
-    /**
-     * Parse zero or more space characters, including at most one newline.
-     */
-    @Override
-    public void spnl() {
-        match(SPNL);
-    }
-
-    /**
-     * Attempt to parse delimiters like emphasis, strong emphasis or custom delimiters.
-     */
-    @Nullable
-    private Node parseDelimiters(DelimiterProcessor delimiterProcessor, char delimiterChar) {
-        DelimiterData res = scanDelimiters(delimiterProcessor, delimiterChar);
-        if (res == null) {
-            return null;
-        }
-        int length = res.count;
-        int startIndex = index;
-
-        index += length;
-        Text node = text(input, startIndex, index);
-
-        // Add entry to stack for this opener
-        lastDelimiter = new Delimiter(node, delimiterChar, res.canOpen, res.canClose, lastDelimiter);
-        lastDelimiter.length = length;
-        lastDelimiter.originalLength = length;
-        if (lastDelimiter.previous != null) {
-            lastDelimiter.previous.next = lastDelimiter;
-        }
-
-        return node;
-    }
-
-    /**
-     * Attempt to parse link destination, returning the string or null if no match.
-     */
-    @Override
-    @Nullable
-    public String parseLinkDestination() {
-        int afterDest = LinkScanner.scanLinkDestination(input, index);
-        if (afterDest == -1) {
-            return null;
-        }
-
-        String dest;
-        if (peek() == '<') {
-            // chop off surrounding <..>:
-            dest = input.substring(index + 1, afterDest - 1);
-        } else {
-            dest = input.substring(index, afterDest);
-        }
-
-        index = afterDest;
-        return Escaping.unescapeString(dest);
-    }
-
-    /**
-     * Attempt to parse link title (sans quotes), returning the string or null if no match.
-     */
-    @Override
-    @Nullable
-    public String parseLinkTitle() {
-        int afterTitle = LinkScanner.scanLinkTitle(input, index);
-        if (afterTitle == -1) {
-            return null;
-        }
-
-        // chop off ', " or parens
-        String title = input.substring(index + 1, afterTitle - 1);
-        index = afterTitle;
-        return Escaping.unescapeString(title);
-    }
-
-    /**
-     * Attempt to parse a link label, returning number of characters parsed.
-     */
-    @Override
-    public int parseLinkLabel() {
-        if (index >= input.length() || input.charAt(index) != '[') {
-            return 0;
-        }
-
-        int startContent = index + 1;
-        int endContent = LinkScanner.scanLinkLabelContent(input, startContent);
-        // spec: A link label can have at most 999 characters inside the square brackets.
-        int contentLength = endContent - startContent;
-        if (endContent == -1 || contentLength > 999) {
-            return 0;
-        }
-        if (endContent >= input.length() || input.charAt(endContent) != ']') {
-            return 0;
-        }
-        index = endContent + 1;
-        return contentLength + 2;
-    }
-
-    /**
-     * Parse a run of ordinary characters, or a single character with a special meaning in markdown, as a plain string.
-     */
-    private Node parseString() {
-        int begin = index;
-        int length = input.length();
-        while (index != length) {
-            if (specialCharacters.get(input.charAt(index))) {
-                break;
-            }
-            index++;
-        }
-        if (begin != index) {
-            return text(input, begin, index);
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Scan a sequence of characters with code delimiterChar, and return information about the number of delimiters
-     * and whether they are positioned such that they can open and/or close emphasis or strong emphasis.
-     *
-     * @return information about delimiter run, or {@code null}
-     */
-    private DelimiterData scanDelimiters(DelimiterProcessor delimiterProcessor, char delimiterChar) {
-        int startIndex = index;
-
-        int delimiterCount = 0;
-        while (peek() == delimiterChar) {
-            delimiterCount++;
-            index++;
-        }
-
-        if (delimiterCount < delimiterProcessor.getMinLength()) {
-            index = startIndex;
-            return null;
-        }
-
-        String before = startIndex == 0 ? "\n" :
-                input.substring(startIndex - 1, startIndex);
-
-        char charAfter = peek();
-        String after = charAfter == '\0' ? "\n" :
-                String.valueOf(charAfter);
-
-        // We could be more lazy here, in most cases we don't need to do every match case.
-        boolean beforeIsPunctuation = PUNCTUATION.matcher(before).matches();
-        boolean beforeIsWhitespace = UNICODE_WHITESPACE_CHAR.matcher(before).matches();
-        boolean afterIsPunctuation = PUNCTUATION.matcher(after).matches();
-        boolean afterIsWhitespace = UNICODE_WHITESPACE_CHAR.matcher(after).matches();
-
-        boolean leftFlanking = !afterIsWhitespace &&
-                (!afterIsPunctuation || beforeIsWhitespace || beforeIsPunctuation);
-        boolean rightFlanking = !beforeIsWhitespace &&
-                (!beforeIsPunctuation || afterIsWhitespace || afterIsPunctuation);
-        boolean canOpen;
-        boolean canClose;
-        if (delimiterChar == '_') {
-            canOpen = leftFlanking && (!rightFlanking || beforeIsPunctuation);
-            canClose = rightFlanking && (!leftFlanking || afterIsPunctuation);
-        } else {
-            canOpen = leftFlanking && delimiterChar == delimiterProcessor.getOpeningCharacter();
-            canClose = rightFlanking && delimiterChar == delimiterProcessor.getClosingCharacter();
-        }
-
-        index = startIndex;
-        return new DelimiterData(delimiterCount, canOpen, canClose);
-    }
-
-    @Override
-    public void processDelimiters(Delimiter stackBottom) {
-
-        Map<Character, Delimiter> openersBottom = new HashMap<>();
-
-        // find first closer above stackBottom:
-        Delimiter closer = lastDelimiter;
-        while (closer != null && closer.previous != stackBottom) {
-            closer = closer.previous;
-        }
-        // move forward, looking for closers, and handling each
-        while (closer != null) {
-            char delimiterChar = closer.delimiterChar;
-
-            DelimiterProcessor delimiterProcessor = delimiterProcessors.get(delimiterChar);
-            if (!closer.canClose || delimiterProcessor == null) {
-                closer = closer.next;
-                continue;
-            }
-
-            char openingDelimiterChar = delimiterProcessor.getOpeningCharacter();
-
-            // Found delimiter closer. Now look back for first matching opener.
-            int useDelims = 0;
-            boolean openerFound = false;
-            boolean potentialOpenerFound = false;
-            Delimiter opener = closer.previous;
-            while (opener != null && opener != stackBottom && opener != openersBottom.get(delimiterChar)) {
-                if (opener.canOpen && opener.delimiterChar == openingDelimiterChar) {
-                    potentialOpenerFound = true;
-                    useDelims = delimiterProcessor.getDelimiterUse(opener, closer);
-                    if (useDelims > 0) {
-                        openerFound = true;
-                        break;
-                    }
-                }
-                opener = opener.previous;
-            }
-
-            if (!openerFound) {
-                if (!potentialOpenerFound) {
-                    // Set lower bound for future searches for openers.
-                    // Only do this when we didn't even have a potential
-                    // opener (one that matches the character and can open).
-                    // If an opener was rejected because of the number of
-                    // delimiters (e.g. because of the "multiple of 3" rule),
-                    // we want to consider it next time because the number
-                    // of delimiters can change as we continue processing.
-                    openersBottom.put(delimiterChar, closer.previous);
-                    if (!closer.canOpen) {
-                        // We can remove a closer that can't be an opener,
-                        // once we've seen there's no matching opener:
-                        removeDelimiterKeepNode(closer);
-                    }
-                }
-                closer = closer.next;
-                continue;
-            }
-
-            Text openerNode = opener.node;
-            Text closerNode = closer.node;
-
-            // Remove number of used delimiters from stack and inline nodes.
-            opener.length -= useDelims;
-            closer.length -= useDelims;
-            openerNode.setLiteral(
-                    openerNode.getLiteral().substring(0,
-                            openerNode.getLiteral().length() - useDelims));
-            closerNode.setLiteral(
-                    closerNode.getLiteral().substring(0,
-                            closerNode.getLiteral().length() - useDelims));
-
-            removeDelimitersBetween(opener, closer);
-            // The delimiter processor can re-parent the nodes between opener and closer,
-            // so make sure they're contiguous already. Exclusive because we want to keep opener/closer themselves.
-            mergeTextNodesBetweenExclusive(openerNode, closerNode);
-            delimiterProcessor.process(openerNode, closerNode, useDelims);
-
-            // No delimiter characters left to process, so we can remove delimiter and the now empty node.
-            if (opener.length == 0) {
-                removeDelimiterAndNode(opener);
-            }
-
-            if (closer.length == 0) {
-                Delimiter next = closer.next;
-                removeDelimiterAndNode(closer);
-                closer = next;
-            }
-        }
-
-        // remove all delimiters
-        while (lastDelimiter != null && lastDelimiter != stackBottom) {
-            removeDelimiterKeepNode(lastDelimiter);
-        }
-    }
-
-    private void removeDelimitersBetween(Delimiter opener, Delimiter closer) {
-        Delimiter delimiter = closer.previous;
-        while (delimiter != null && delimiter != opener) {
-            Delimiter previousDelimiter = delimiter.previous;
-            removeDelimiterKeepNode(delimiter);
-            delimiter = previousDelimiter;
-        }
-    }
-
-    /**
-     * Remove the delimiter and the corresponding text node. For used delimiters, e.g. `*` in `*foo*`.
-     */
-    private void removeDelimiterAndNode(Delimiter delim) {
-        Text node = delim.node;
-        node.unlink();
-        removeDelimiter(delim);
-    }
-
-    /**
-     * Remove the delimiter but keep the corresponding node as text. For unused delimiters such as `_` in `foo_bar`.
-     */
-    private void removeDelimiterKeepNode(Delimiter delim) {
-        removeDelimiter(delim);
-    }
-
-    private void removeDelimiter(Delimiter delim) {
-        if (delim.previous != null) {
-            delim.previous.next = delim.next;
-        }
-        if (delim.next == null) {
-            // top of stack
-            lastDelimiter = delim.previous;
-        } else {
-            delim.next.previous = delim.previous;
-        }
-    }
-
-    private static class DelimiterData {
-
-        final int count;
-        final boolean canClose;
-        final boolean canOpen;
-
-        DelimiterData(int count, boolean canOpen, boolean canClose) {
-            this.count = count;
-            this.canOpen = canOpen;
-            this.canClose = canClose;
-        }
-    }
-
-    static class FactoryBuilderImpl implements FactoryBuilder, FactoryBuilderNoDefaults {
-
-        private final List<InlineProcessor> inlineProcessors = new ArrayList<>(3);
-        private final List<DelimiterProcessor> delimiterProcessors = new ArrayList<>(3);
-        private boolean referencesEnabled;
-
-        @NonNull
-        @Override
-        public FactoryBuilder addInlineProcessor(@NonNull InlineProcessor processor) {
-            this.inlineProcessors.add(processor);
-            return this;
-        }
-
-        @NonNull
-        @Override
-        public FactoryBuilder addDelimiterProcessor(@NonNull DelimiterProcessor processor) {
-            this.delimiterProcessors.add(processor);
-            return this;
-        }
-
-        @NonNull
-        @Override
-        public FactoryBuilder referencesEnabled(boolean referencesEnabled) {
-            this.referencesEnabled = referencesEnabled;
-            return this;
-        }
-
-        @NonNull
-        @Override
-        public FactoryBuilder includeDefaults() {
-
-            // by default enabled
-            this.referencesEnabled = true;
-
-            this.inlineProcessors.addAll(Arrays.asList(
-                    new AutolinkInlineProcessor(),
-                    new BackslashInlineProcessor(),
-                    new BackticksInlineProcessor(),
-                    new BangInlineProcessor(),
-                    new CloseBracketInlineProcessor(),
-                    new EntityInlineProcessor(),
-                    new HtmlInlineProcessor(),
-                    new NewLineInlineProcessor(),
-                    new OpenBracketInlineProcessor()));
-
-            this.delimiterProcessors.addAll(Arrays.asList(
-                    new AsteriskDelimiterProcessor(),
-                    new UnderscoreDelimiterProcessor()));
-
-            return this;
-        }
-
-        @NonNull
-        @Override
-        public FactoryBuilder excludeInlineProcessor(@NonNull Class<? extends InlineProcessor> type) {
-            for (int i = 0, size = inlineProcessors.size(); i < size; i++) {
-                if (type.equals(inlineProcessors.get(i).getClass())) {
-                    inlineProcessors.remove(i);
-                    break;
-                }
-            }
-            return this;
-        }
-
-        @NonNull
-        @Override
-        public FactoryBuilder excludeDelimiterProcessor(@NonNull Class<? extends DelimiterProcessor> type) {
-            for (int i = 0, size = delimiterProcessors.size(); i < size; i++) {
-                if (type.equals(delimiterProcessors.get(i).getClass())) {
-                    delimiterProcessors.remove(i);
-                    break;
-                }
-            }
-            return this;
-        }
-
-        @NonNull
-        @Override
-        public InlineParserFactory build() {
-            return new InlineParserFactoryImpl(referencesEnabled, inlineProcessors, delimiterProcessors);
-        }
-    }
-
-    static class InlineParserFactoryImpl implements InlineParserFactory {
-
-        private final boolean referencesEnabled;
-        private final List<InlineProcessor> inlineProcessors;
-        private final List<DelimiterProcessor> delimiterProcessors;
-
-        InlineParserFactoryImpl(
-                boolean referencesEnabled,
-                @NonNull List<InlineProcessor> inlineProcessors,
-                @NonNull List<DelimiterProcessor> delimiterProcessors) {
-            this.referencesEnabled = referencesEnabled;
-            this.inlineProcessors = inlineProcessors;
-            this.delimiterProcessors = delimiterProcessors;
-        }
-
-        @Override
-        public InlineParser create(InlineParserContext inlineParserContext) {
-            final List<DelimiterProcessor> delimiterProcessors;
-            final List<DelimiterProcessor> customDelimiterProcessors = inlineParserContext.getCustomDelimiterProcessors();
-            final int size = customDelimiterProcessors != null
-                    ? customDelimiterProcessors.size()
-                    : 0;
-            if (size > 0) {
-                delimiterProcessors = new ArrayList<>(size + this.delimiterProcessors.size());
-                delimiterProcessors.addAll(this.delimiterProcessors);
-                delimiterProcessors.addAll(customDelimiterProcessors);
-            } else {
-                delimiterProcessors = this.delimiterProcessors;
-            }
-            return new MarkwonInlineParser(
-                    inlineParserContext,
-                    referencesEnabled,
-                    inlineProcessors,
-                    delimiterProcessors);
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserContext.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserContext.java
deleted file mode 100644
index 46870f91..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserContext.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.commonmark.internal.Bracket;
-import org.commonmark.internal.Delimiter;
-import org.commonmark.node.Link;
-import org.commonmark.node.LinkReferenceDefinition;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-import java.util.Map;
-import java.util.regex.Pattern;
-
-public interface MarkwonInlineParserContext {
-
-    @NonNull
-    Node block();
-
-    @NonNull
-    String input();
-
-    int index();
-
-    void setIndex(int index);
-
-    Bracket lastBracket();
-
-    Delimiter lastDelimiter();
-
-    void addBracket(Bracket bracket);
-
-    void removeLastBracket();
-
-    void spnl();
-
-    /**
-     * Returns the char at the current input index, or {@code '\0'} in case there are no more characters.
-     */
-    char peek();
-
-    @Nullable
-    String match(@NonNull Pattern re);
-
-    @NonNull
-    Text text(@NonNull String text);
-
-    @NonNull
-    Text text(@NonNull String text, int beginIndex, int endIndex);
-
-    @Nullable
-    LinkReferenceDefinition getLinkReferenceDefinition(String label);
-
-    @Nullable
-    String parseLinkDestination();
-
-    @Nullable
-    String parseLinkTitle();
-
-    int parseLinkLabel();
-
-    void processDelimiters(Delimiter stackBottom);
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserPlugin.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserPlugin.java
deleted file mode 100644
index 470e2fb8..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/MarkwonInlineParserPlugin.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import androidx.annotation.NonNull;
-
-import org.commonmark.parser.Parser;
-
-import io.noties.markwon.AbstractMarkwonPlugin;
-
-/**
- * @since 4.3.0
- */
-public class MarkwonInlineParserPlugin extends AbstractMarkwonPlugin {
-
-    public interface BuilderConfigure<B extends MarkwonInlineParser.FactoryBuilder> {
-        void configureBuilder(@NonNull B factoryBuilder);
-    }
-
-    @NonNull
-    public static MarkwonInlineParserPlugin create() {
-        return create(MarkwonInlineParser.factoryBuilder());
-    }
-
-    @NonNull
-    public static MarkwonInlineParserPlugin create(@NonNull BuilderConfigure<MarkwonInlineParser.FactoryBuilder> configure) {
-        final MarkwonInlineParser.FactoryBuilder factoryBuilder = MarkwonInlineParser.factoryBuilder();
-        configure.configureBuilder(factoryBuilder);
-        return new MarkwonInlineParserPlugin(factoryBuilder);
-    }
-
-    @NonNull
-    public static MarkwonInlineParserPlugin create(@NonNull MarkwonInlineParser.FactoryBuilder factoryBuilder) {
-        return new MarkwonInlineParserPlugin(factoryBuilder);
-    }
-
-    @NonNull
-    public static <B extends MarkwonInlineParser.FactoryBuilder> MarkwonInlineParserPlugin create(
-            @NonNull B factoryBuilder,
-            @NonNull BuilderConfigure<B> configure) {
-        configure.configureBuilder(factoryBuilder);
-        return new MarkwonInlineParserPlugin(factoryBuilder);
-    }
-
-    private final MarkwonInlineParser.FactoryBuilder factoryBuilder;
-
-    @SuppressWarnings("WeakerAccess")
-    MarkwonInlineParserPlugin(@NonNull MarkwonInlineParser.FactoryBuilder factoryBuilder) {
-        this.factoryBuilder = factoryBuilder;
-    }
-
-    @Override
-    public void configureParser(@NonNull Parser.Builder builder) {
-        builder.inlineParserFactory(factoryBuilder.build());
-    }
-
-    @NonNull
-    public MarkwonInlineParser.FactoryBuilder factoryBuilder() {
-        return factoryBuilder;
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/NewLineInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/NewLineInlineProcessor.java
deleted file mode 100644
index ef978b72..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/NewLineInlineProcessor.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.node.HardLineBreak;
-import org.commonmark.node.Node;
-import org.commonmark.node.SoftLineBreak;
-import org.commonmark.node.Text;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @since 4.2.0
- */
-public class NewLineInlineProcessor extends InlineProcessor {
-
-    private static final Pattern FINAL_SPACE = Pattern.compile(" *$");
-
-    @Override
-    public char specialCharacter() {
-        return '\n';
-    }
-
-    @Override
-    protected Node parse() {
-        index++; // assume we're at a \n
-
-        final Node previous = block.getLastChild();
-
-        // Check previous text for trailing spaces.
-        // The "endsWith" is an optimization to avoid an RE match in the common case.
-        if (previous instanceof Text && ((Text) previous).getLiteral().endsWith(" ")) {
-            Text text = (Text) previous;
-            String literal = text.getLiteral();
-            Matcher matcher = FINAL_SPACE.matcher(literal);
-            int spaces = matcher.find() ? matcher.end() - matcher.start() : 0;
-            if (spaces > 0) {
-                text.setLiteral(literal.substring(0, literal.length() - spaces));
-            }
-            if (spaces >= 2) {
-                return new HardLineBreak();
-            } else {
-                return new SoftLineBreak();
-            }
-        } else {
-            return new SoftLineBreak();
-        }
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/OpenBracketInlineProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/OpenBracketInlineProcessor.java
deleted file mode 100644
index 070d9ccc..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/OpenBracketInlineProcessor.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.internal.Bracket;
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-
-/**
- * Parses markdown links {@code [link](#href)}
- *
- * @since 4.2.0
- */
-public class OpenBracketInlineProcessor extends InlineProcessor {
-    @Override
-    public char specialCharacter() {
-        return '[';
-    }
-
-    @Override
-    protected Node parse() {
-        int startIndex = index;
-        index++;
-
-        Text node = text("[");
-
-        // Add entry to stack for this opener
-        addBracket(Bracket.link(node, startIndex, lastBracket(), lastDelimiter()));
-
-        return node;
-    }
-}
diff --git a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/StaggeredDelimiterProcessor.java b/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/StaggeredDelimiterProcessor.java
deleted file mode 100644
index c2a92c3d..00000000
--- a/markwon-inline-parser/src/main/java/io/noties/markwon/inlineparser/StaggeredDelimiterProcessor.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.node.Text;
-import org.commonmark.parser.delimiter.DelimiterProcessor;
-import org.commonmark.parser.delimiter.DelimiterRun;
-
-import java.util.LinkedList;
-import java.util.ListIterator;
-
-class StaggeredDelimiterProcessor implements DelimiterProcessor {
-
-    private final char delim;
-    private int minLength = 0;
-    private LinkedList<DelimiterProcessor> processors = new LinkedList<>(); // in reverse getMinLength order
-
-    StaggeredDelimiterProcessor(char delim) {
-        this.delim = delim;
-    }
-
-    @Override
-    public char getOpeningCharacter() {
-        return delim;
-    }
-
-    @Override
-    public char getClosingCharacter() {
-        return delim;
-    }
-
-    @Override
-    public int getMinLength() {
-        return minLength;
-    }
-
-    void add(DelimiterProcessor dp) {
-        final int len = dp.getMinLength();
-        ListIterator<DelimiterProcessor> it = processors.listIterator();
-        boolean added = false;
-        while (it.hasNext()) {
-            DelimiterProcessor p = it.next();
-            int pLen = p.getMinLength();
-            if (len > pLen) {
-                it.previous();
-                it.add(dp);
-                added = true;
-                break;
-            } else if (len == pLen) {
-                throw new IllegalArgumentException("Cannot add two delimiter processors for char '" + delim + "' and minimum length " + len);
-            }
-        }
-        if (!added) {
-            processors.add(dp);
-            this.minLength = len;
-        }
-    }
-
-    private DelimiterProcessor findProcessor(int len) {
-        for (DelimiterProcessor p : processors) {
-            if (p.getMinLength() <= len) {
-                return p;
-            }
-        }
-        return processors.getFirst();
-    }
-
-    @Override
-    public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) {
-        return findProcessor(opener.length()).getDelimiterUse(opener, closer);
-    }
-
-    @Override
-    public void process(Text opener, Text closer, int delimiterUse) {
-        findProcessor(delimiterUse).process(opener, closer, delimiterUse);
-    }
-}
diff --git a/markwon-inline-parser/src/test/java/io/noties/markwon/inlineparser/InlineParserSpecTest.java b/markwon-inline-parser/src/test/java/io/noties/markwon/inlineparser/InlineParserSpecTest.java
deleted file mode 100644
index b7afb01d..00000000
--- a/markwon-inline-parser/src/test/java/io/noties/markwon/inlineparser/InlineParserSpecTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.noties.markwon.inlineparser;
-
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-import org.commonmark.testutil.SpecTestCase;
-import org.commonmark.testutil.example.Example;
-
-public class InlineParserSpecTest extends SpecTestCase {
-
-    private static final Parser PARSER = Parser.builder()
-            .inlineParserFactory(MarkwonInlineParser.factoryBuilder().build())
-            .build();
-
-    // The spec says URL-escaping is optional, but the examples assume that it's enabled.
-    private static final HtmlRenderer RENDERER = HtmlRenderer.builder().percentEncodeUrls(true).build();
-
-    public InlineParserSpecTest(Example example) {
-        super(example);
-    }
-
-    @Override
-    protected String render(String source) {
-        return RENDERER.render(PARSER.parse(source));
-    }
-}
diff --git a/markwon-linkify/build.gradle b/markwon-linkify/build.gradle
index 39f8eecf..fec2ee9a 100644
--- a/markwon-linkify/build.gradle
+++ b/markwon-linkify/build.gradle
@@ -24,3 +24,4 @@ dependencies {
 }
 
 registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java b/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java
index ded176f6..a58ee0c2 100644
--- a/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java
+++ b/markwon-linkify/src/main/java/io/noties/markwon/linkify/LinkifyPlugin.java
@@ -9,7 +9,7 @@ import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.core.text.util.LinkifyCompat;
 
-import org.commonmark.node.Link;
+import com.vladsch.flexmark.ast.Link;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/markwon-recycler-table/build.gradle b/markwon-recycler-table/build.gradle
index 841c2b60..757e5877 100644
--- a/markwon-recycler-table/build.gradle
+++ b/markwon-recycler-table/build.gradle
@@ -26,4 +26,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java
index 2784221f..70523252 100644
--- a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java
+++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntry.java
@@ -19,7 +19,7 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Px;
 import androidx.annotation.VisibleForTesting;
 
-import org.commonmark.ext.gfm.tables.TableBlock;
+import com.vladsch.flexmark.ext.tables.TableBlock;
 
 import java.util.HashMap;
 import java.util.List;
diff --git a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java
index b917bb19..6e7834f1 100644
--- a/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java
+++ b/markwon-recycler-table/src/main/java/io/noties/markwon/recycler/table/TableEntryPlugin.java
@@ -4,8 +4,9 @@ import android.content.Context;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.ext.gfm.tables.TablesExtension;
-import org.commonmark.parser.Parser;
+
+import com.vladsch.flexmark.ext.tables.TablesExtension;
+import com.vladsch.flexmark.parser.Parser;
 
 import java.util.Collections;
 
diff --git a/markwon-recycler/build.gradle b/markwon-recycler/build.gradle
index 63c7742e..857cb9d3 100644
--- a/markwon-recycler/build.gradle
+++ b/markwon-recycler/build.gradle
@@ -22,4 +22,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java
index 265c9273..f0af0802 100644
--- a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java
+++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapter.java
@@ -10,7 +10,7 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.List;
 
diff --git a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java
index d773edcc..bfefce28 100644
--- a/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java
+++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/MarkwonAdapterImpl.java
@@ -6,7 +6,7 @@ import android.view.ViewGroup;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.Collections;
 import java.util.List;
diff --git a/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java b/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java
index b55be1fb..6b4a3e23 100644
--- a/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java
+++ b/markwon-recycler/src/main/java/io/noties/markwon/recycler/SimpleEntry.java
@@ -10,7 +10,7 @@ import androidx.annotation.IdRes;
 import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
+import com.vladsch.flexmark.util.ast.Node;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/markwon-simple-ext/build.gradle b/markwon-simple-ext/build.gradle
index 39dc63da..c9e58114 100644
--- a/markwon-simple-ext/build.gradle
+++ b/markwon-simple-ext/build.gradle
@@ -24,4 +24,5 @@ dependencies {
     }
 }
 
-registerArtifact(this)
\ No newline at end of file
+registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java
index 927ba3f0..5da5d1e3 100644
--- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java
+++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtBuilder.java
@@ -2,7 +2,8 @@ package io.noties.markwon.simple.ext;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.parser.delimiter.DelimiterProcessor;
+
+import com.vladsch.flexmark.parser.delimiter.DelimiterProcessor;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java
index 924525b0..0b895821 100644
--- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java
+++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtDelimiterProcessor.java
@@ -2,10 +2,11 @@ package io.noties.markwon.simple.ext;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.Node;
-import org.commonmark.node.Text;
-import org.commonmark.parser.delimiter.DelimiterProcessor;
-import org.commonmark.parser.delimiter.DelimiterRun;
+import com.vladsch.flexmark.parser.InlineParser;
+import com.vladsch.flexmark.parser.core.delimiter.Delimiter;
+import com.vladsch.flexmark.parser.delimiter.DelimiterProcessor;
+import com.vladsch.flexmark.parser.delimiter.DelimiterRun;
+import com.vladsch.flexmark.util.ast.Node;
 
 import io.noties.markwon.SpanFactory;
 
@@ -52,19 +53,37 @@ class SimpleExtDelimiterProcessor implements DelimiterProcessor {
     }
 
     @Override
-    public void process(Text opener, Text closer, int delimiterUse) {
-
+    public void process(Delimiter opener, Delimiter closer, int delimitersUsed) {
         final Node node = new SimpleExtNode(spanFactory);
-
-        Node tmp = opener.getNext();
-        Node next;
+        Delimiter tmp = opener.getNext();
+        Delimiter next;
 
         while (tmp != null && tmp != closer) {
             next = tmp.getNext();
-            node.appendChild(tmp);
+            node.appendChild(tmp.getNode());
             tmp = next;
         }
 
-        opener.insertAfter(node);
+        opener.getNode().insertAfter(node);
+    }
+
+    @Override
+    public Node unmatchedDelimiterNode(InlineParser inlineParser, DelimiterRun delimiter) {
+        return null;
+    }
+
+    @Override
+    public boolean canBeOpener(String before, String after, boolean leftFlanking, boolean rightFlanking, boolean beforeIsPunctuation, boolean afterIsPunctuation, boolean beforeIsWhitespace, boolean afterIsWhiteSpace) {
+        return false;
+    }
+
+    @Override
+    public boolean canBeCloser(String before, String after, boolean leftFlanking, boolean rightFlanking, boolean beforeIsPunctuation, boolean afterIsPunctuation, boolean beforeIsWhitespace, boolean afterIsWhiteSpace) {
+        return false;
+    }
+
+    @Override
+    public boolean skipNonOpenerCloser() {
+        return false;
     }
 }
diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java
index 8d1173c3..2259c704 100644
--- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java
+++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtNode.java
@@ -2,13 +2,15 @@ package io.noties.markwon.simple.ext;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.node.CustomNode;
-import org.commonmark.node.Visitor;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.sequence.BasedSequence;
+
+import org.jetbrains.annotations.NotNull;
 
 import io.noties.markwon.SpanFactory;
 
 // @since 4.0.0
-class SimpleExtNode extends CustomNode {
+class SimpleExtNode extends Node {
 
     private final SpanFactory spanFactory;
 
@@ -16,13 +18,14 @@ class SimpleExtNode extends CustomNode {
         this.spanFactory = spanFactory;
     }
 
-    @Override
-    public void accept(Visitor visitor) {
-        visitor.visit(this);
-    }
-
     @NonNull
     SpanFactory spanFactory() {
         return spanFactory;
     }
+
+    @NonNull
+    @Override
+    public @NotNull BasedSequence[] getSegments() {
+        return BasedSequence.EMPTY_SEGMENTS;
+    }
 }
diff --git a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java
index a5d2cf8c..9a34b2a6 100644
--- a/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java
+++ b/markwon-simple-ext/src/main/java/io/noties/markwon/simple/ext/SimpleExtPlugin.java
@@ -2,8 +2,8 @@ package io.noties.markwon.simple.ext;
 
 import androidx.annotation.NonNull;
 
-import org.commonmark.parser.Parser;
-import org.commonmark.parser.delimiter.DelimiterProcessor;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.parser.delimiter.DelimiterProcessor;
 
 import io.noties.markwon.AbstractMarkwonPlugin;
 import io.noties.markwon.MarkwonVisitor;
diff --git a/markwon-syntax-highlight/build.gradle b/markwon-syntax-highlight/build.gradle
index 4c6586ed..3f6fb645 100644
--- a/markwon-syntax-highlight/build.gradle
+++ b/markwon-syntax-highlight/build.gradle
@@ -23,3 +23,4 @@ dependencies {
 }
 
 registerArtifact(this)
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
\ No newline at end of file
diff --git a/markwon-test-span/build.gradle b/markwon-test-span/build.gradle
index bdf64b2e..68415f0a 100644
--- a/markwon-test-span/build.gradle
+++ b/markwon-test-span/build.gradle
@@ -21,4 +21,4 @@ dependencies {
     deps['test'].with {
         api it['junit']
     }
-}
+}
\ No newline at end of file
diff --git a/sample-utils/processor/build.gradle b/sample-utils/processor/build.gradle
index d2664b3f..ba1aeb79 100644
--- a/sample-utils/processor/build.gradle
+++ b/sample-utils/processor/build.gradle
@@ -1,8 +1,5 @@
 apply plugin: 'java-library'
 
-sourceCompatibility = JavaVersion.VERSION_1_8
-targetCompatibility = JavaVersion.VERSION_1_8
-
 sourceSets {
     main.java.srcDirs += '../annotations'
 }
diff --git a/settings.gradle b/settings.gradle
index 7811c39e..c3430d41 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -10,7 +10,6 @@ include ':markwon-core',
         ':markwon-image-coil',
         ':markwon-image-glide',
         ':markwon-image-picasso',
-        ':markwon-inline-parser',
         ':markwon-linkify',
         ':markwon-recycler',
         ':markwon-recycler-table',