66import org .commonmark .ext .gfm .alerts .internal .AlertMarkdownNodeRenderer ;
77import org .commonmark .parser .Parser ;
88import org .commonmark .renderer .NodeRenderer ;
9+ import org .commonmark .renderer .html .HtmlNodeRendererContext ;
10+ import org .commonmark .renderer .html .HtmlNodeRendererFactory ;
911import org .commonmark .renderer .html .HtmlRenderer ;
1012import org .commonmark .renderer .markdown .MarkdownNodeRendererContext ;
1113import org .commonmark .renderer .markdown .MarkdownNodeRendererFactory ;
4951public class AlertsExtension implements Parser .ParserExtension , HtmlRenderer .HtmlRendererExtension ,
5052 MarkdownRenderer .MarkdownRendererExtension {
5153
52- static final Set <String > STANDARD_TYPES = Set .of ("NOTE" , "TIP" , "IMPORTANT" , "WARNING" , "CAUTION" );
54+ /**
55+ * The standard GitHub Flavored Markdown (GFM) types that the extension
56+ * enables by default. They can be removed individually with
57+ * {@link Builder#removeType(String)}.
58+ */
59+ public static final Map <String , String > STANDARD_TYPES = Map .ofEntries (
60+ Map .entry ("NOTE" , "Note" ),
61+ Map .entry ("TIP" , "Tip" ),
62+ Map .entry ("IMPORTANT" , "Important" ),
63+ Map .entry ("WARNING" , "Warning" ),
64+ Map .entry ("CAUTION" , "Caution" )
65+ );
5366
54- private final Map <String , String > customTypes ;
67+ /**
68+ * A map of alert marker ({@code [!TYPE]}) to the default title for that marker.
69+ */
70+ private final Map <String , String > allowedTypes ;
5571 private final boolean customTitlesAllowed ;
5672 private final boolean nestedAlertsAllowed ;
5773
5874 private AlertsExtension (Builder builder ) {
59- this .customTypes = new HashMap <>(builder .customTypes );
75+ this .allowedTypes = new HashMap <>(builder .allowedTypes );
6076 this .customTitlesAllowed = builder .customTitlesAllowed ;
6177 this .nestedAlertsAllowed = builder .nestedAlertsAllowed ;
6278 }
@@ -71,15 +87,19 @@ public static Builder builder() {
7187
7288 @ Override
7389 public void extend (Parser .Builder parserBuilder ) {
74- var allowedTypes = new HashSet <>(STANDARD_TYPES );
75- allowedTypes .addAll (customTypes .keySet ());
90+ var allowedTypesSet = new HashSet <>(allowedTypes .keySet ());
7691 parserBuilder .customBlockParserFactory (
77- new AlertBlockParser .Factory (allowedTypes , customTitlesAllowed , nestedAlertsAllowed ));
92+ new AlertBlockParser .Factory (allowedTypesSet , customTitlesAllowed , nestedAlertsAllowed ));
7893 }
7994
8095 @ Override
8196 public void extend (HtmlRenderer .Builder rendererBuilder ) {
82- rendererBuilder .nodeRendererFactory (context -> new AlertHtmlNodeRenderer (context , customTypes ));
97+ rendererBuilder .nodeRendererFactory (new HtmlNodeRendererFactory () {
98+ @ Override
99+ public NodeRenderer create (HtmlNodeRendererContext context ) {
100+ return new AlertHtmlNodeRenderer (context , allowedTypes );
101+ }
102+ });
83103 }
84104
85105 @ Override
@@ -101,18 +121,18 @@ public Set<Character> getSpecialCharacters() {
101121 * Builder for configuring the alerts extension.
102122 */
103123 public static class Builder {
104- private final Map <String , String > customTypes = new HashMap <>();
124+ private final Map <String , String > allowedTypes = new HashMap <>(STANDARD_TYPES );
105125 private boolean customTitlesAllowed = false ;
106126 private boolean nestedAlertsAllowed = false ;
107127
108128 /**
109- * Adds a custom alert type with a display title.
129+ * Adds a custom alert type with a default title.
110130 * <p>
111- * This can also be used to override the display title of standard GFM types
131+ * This can also be used to override the default title of standard GFM types
112132 * (e.g., for localization).
113133 *
114134 * @param type the alert type (must be uppercase)
115- * @param title the display title for this alert type
135+ * @param title the default title for this alert type
116136 * @return {@code this}
117137 */
118138 public Builder addCustomType (String type , String title ) {
@@ -125,7 +145,24 @@ public Builder addCustomType(String type, String title) {
125145 if (!type .equals (type .toUpperCase (Locale .ROOT ))) {
126146 throw new IllegalArgumentException ("Type must be uppercase: " + type );
127147 }
128- customTypes .put (type , title );
148+ allowedTypes .put (type , title );
149+ return this ;
150+ }
151+
152+ /**
153+ * Removes an alert type.
154+ *
155+ * @param type the alert type to remove (must be uppercase)
156+ * @return {@code this}
157+ */
158+ public Builder removeType (String type ) {
159+ if (type == null || type .isEmpty ()) {
160+ throw new IllegalArgumentException ("Type must not be null or empty" );
161+ }
162+ if (!type .equals (type .toUpperCase (Locale .ROOT ))) {
163+ throw new IllegalArgumentException ("Type must be uppercase: " + type );
164+ }
165+ allowedTypes .remove (type );
129166 return this ;
130167 }
131168
0 commit comments