From 2f67ab7110f1ac8dcded4499e45ac791d176ff11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Marx=20=E3=8B=A1?= Date: Thu, 25 Jan 2024 17:24:43 +0100 Subject: [PATCH] GFM compatible alerts (#53) --- README.md | 95 +++++++----- .../io/github/gitbucket/markedj/Lexer.java | 24 +-- .../io/github/gitbucket/markedj/Options.java | 7 +- .../gfm/alert/DefaultGFMAlertRenderer.java | 39 +++++ .../alert/GFMAlertEndToken.java} | 9 +- .../alert/GFMAlertExtension.java} | 73 +++++---- .../extension/gfm/alert/GFMAlertOptions.java | 48 ++++++ .../extension/gfm/alert/GFMAlertRenderer.java | 25 ++++ .../alert/GFMAlertStartToken.java} | 16 +- .../extension/gfm/alert/GFMAlerts.java | 42 ++++++ .../extension/notification/Notifications.java | 53 ------- .../gitbucket/markedj/GFMAlertsTest.java | 141 ++++++++++++++++++ .../gitbucket/markedj/NotificationsTest.java | 88 ----------- src/test/resources/gfm/alerts/caution.html | 4 + src/test/resources/gfm/alerts/caution.md | 2 + src/test/resources/gfm/alerts/important.html | 4 + src/test/resources/gfm/alerts/important.md | 2 + src/test/resources/gfm/alerts/note.html | 4 + src/test/resources/gfm/alerts/note.md | 3 + .../gfm/alerts/testWithMultipleAlerts.html | 8 + .../gfm/alerts/testWithMultipleAlerts.md | 6 + .../testWithParagraphBeforeAndAfter.html | 6 + .../alerts/testWithParagraphBeforeAndAfter.md | 7 + src/test/resources/gfm/alerts/tip.html | 4 + src/test/resources/gfm/alerts/tip.md | 2 + src/test/resources/gfm/alerts/warning.html | 4 + src/test/resources/gfm/alerts/warning.md | 2 + .../gfm/alerts/warning_custom_renderer.html | 4 + .../gfm/alerts/warning_custom_title.html | 4 + .../notifications/embedded_notifications.html | 8 - .../notifications/embedded_notifications.md | 6 - src/test/resources/notifications/error.html | 4 - src/test/resources/notifications/error.md | 2 - src/test/resources/notifications/info.html | 4 - src/test/resources/notifications/info.md | 2 - .../multiple_notifications_1.html | 9 -- .../notifications/multiple_notifications_1.md | 5 - .../multiple_notifications_2.html | 5 - .../notifications/multiple_notifications_2.md | 4 - .../multiple_notifications_3.html | 5 - .../notifications/multiple_notifications_3.md | 5 - .../multiple_notifications_type_change.html | 11 -- .../multiple_notifications_type_change.md | 6 - src/test/resources/notifications/success.html | 4 - src/test/resources/notifications/success.md | 2 - src/test/resources/notifications/warning.html | 4 - src/test/resources/notifications/warning.md | 2 - 47 files changed, 493 insertions(+), 321 deletions(-) create mode 100644 src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/DefaultGFMAlertRenderer.java rename src/main/java/io/github/gitbucket/markedj/extension/{notification/NotificationEndToken.java => gfm/alert/GFMAlertEndToken.java} (80%) rename src/main/java/io/github/gitbucket/markedj/extension/{notification/NotificationExtension.java => gfm/alert/GFMAlertExtension.java} (51%) create mode 100644 src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertOptions.java create mode 100644 src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertRenderer.java rename src/main/java/io/github/gitbucket/markedj/extension/{notification/NotificationStartToken.java => gfm/alert/GFMAlertStartToken.java} (64%) create mode 100644 src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlerts.java delete mode 100644 src/main/java/io/github/gitbucket/markedj/extension/notification/Notifications.java create mode 100644 src/test/java/io/github/gitbucket/markedj/GFMAlertsTest.java delete mode 100644 src/test/java/io/github/gitbucket/markedj/NotificationsTest.java create mode 100644 src/test/resources/gfm/alerts/caution.html create mode 100644 src/test/resources/gfm/alerts/caution.md create mode 100644 src/test/resources/gfm/alerts/important.html create mode 100644 src/test/resources/gfm/alerts/important.md create mode 100644 src/test/resources/gfm/alerts/note.html create mode 100644 src/test/resources/gfm/alerts/note.md create mode 100644 src/test/resources/gfm/alerts/testWithMultipleAlerts.html create mode 100644 src/test/resources/gfm/alerts/testWithMultipleAlerts.md create mode 100644 src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.html create mode 100644 src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.md create mode 100644 src/test/resources/gfm/alerts/tip.html create mode 100644 src/test/resources/gfm/alerts/tip.md create mode 100644 src/test/resources/gfm/alerts/warning.html create mode 100644 src/test/resources/gfm/alerts/warning.md create mode 100644 src/test/resources/gfm/alerts/warning_custom_renderer.html create mode 100644 src/test/resources/gfm/alerts/warning_custom_title.html delete mode 100644 src/test/resources/notifications/embedded_notifications.html delete mode 100644 src/test/resources/notifications/embedded_notifications.md delete mode 100644 src/test/resources/notifications/error.html delete mode 100644 src/test/resources/notifications/error.md delete mode 100644 src/test/resources/notifications/info.html delete mode 100644 src/test/resources/notifications/info.md delete mode 100644 src/test/resources/notifications/multiple_notifications_1.html delete mode 100644 src/test/resources/notifications/multiple_notifications_1.md delete mode 100644 src/test/resources/notifications/multiple_notifications_2.html delete mode 100644 src/test/resources/notifications/multiple_notifications_2.md delete mode 100644 src/test/resources/notifications/multiple_notifications_3.html delete mode 100644 src/test/resources/notifications/multiple_notifications_3.md delete mode 100644 src/test/resources/notifications/multiple_notifications_type_change.html delete mode 100644 src/test/resources/notifications/multiple_notifications_type_change.md delete mode 100644 src/test/resources/notifications/success.html delete mode 100644 src/test/resources/notifications/success.md delete mode 100644 src/test/resources/notifications/warning.html delete mode 100644 src/test/resources/notifications/warning.md diff --git a/README.md b/README.md index 413ef60..a170c0c 100644 --- a/README.md +++ b/README.md @@ -67,67 +67,92 @@ Extensions can be used by adding them to the options. ```java Options options = new Options(); -options.addExtension(new NotificationExtension()); -String html = Marked.marked("! This is an info message", options); - // =>

This is an info message

+options.addExtension(new GFMAlertExtension()); +String html = Marked.marked("> [!NOTE]\n> This is a note!", options); ``` -### Notification extension +### GFMAlert extension -The notification extension helps you to add information messages to your markdown content. -Keep in mind, you still need the CSS to style the messages as desired. +Support for github like [alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts). -#### Info message -```text -! This is an info message +For styling, some project-specific CSS is required. SVG icons are embedded but can be replaced by configuration. + +#### Usage + +```java +Options options = new Options(); +// Override default title for note alert +GFMAlertOptions alertOptions = new GFMAlertOptions(); +alertOptions.setTitle(GFMAlerts.Alert.WARNING, "Attention!!!"); +GFMAlertExtension gfmAlerts = new GFMAlertExtension(alertOptions); +options.addExtension(gfmAlerts); +String html = Marked.marked("> [!NOTE]\n> This is a note!", options); ``` + +#### Supported alert types + +**Note** +```markdown +> [!NOTE] +> Useful information that users should know, even when skimming content. +``` +**Note HTML** ```html -
-

This is an info message

+
+

Note

+

Useful information that users should know, even when skimming content.

``` -#### Success message -```text -!v This is a success message +**Tip** +```markdown +> [!TIP] +> Helpful advice for doing things better or more easily. ``` +**Tip HTML** ```html -
-

This is a success message

+
+

Tip

+

Helpful advice for doing things better or more easily.

``` -#### Warning message -```text -!! This is a warning message +**Important** +```markdown +> [!IMPORTANT] +> Key information users need to know to achieve their goal. ``` +**Important HTML** ```html -
-

This is a warning message

+
+

Important

+

Key information users need to know to achieve their goal.

``` -#### Error message -```text -!x This is an error message +**Warning** +```markdown +> [!WARNING] +> Urgent info that needs immediate user attention to avoid problems. ``` +**Warning HTML** ```html -
-

This is an error message

+
+

Warning

+

Urgent info that needs immediate user attention to avoid problems.

``` -#### Multiline notifications -Notifications can span multiple lines. - -```text -! This is an info message -! That spans over several lines +**Caution** +```markdown +> [!CAUTION] +> Advises about risks or negative outcomes of certain actions. ``` +**Caution HTML** ```html -
-

This is an info message -That spans over several lines

+
+

Caution

+

Advises about risks or negative outcomes of certain actions.

``` diff --git a/src/main/java/io/github/gitbucket/markedj/Lexer.java b/src/main/java/io/github/gitbucket/markedj/Lexer.java index 7690b54..418e1ee 100644 --- a/src/main/java/io/github/gitbucket/markedj/Lexer.java +++ b/src/main/java/io/github/gitbucket/markedj/Lexer.java @@ -159,18 +159,6 @@ protected void token(String src, boolean top, boolean bq, LexerContext context){ } } - // blockquote - { - List cap = rules.get("blockquote").exec(src); - if(!cap.isEmpty()){ - src = src.substring(cap.get(0).length()); - context.pushToken(new BlockquoteStartToken()); - token(cap.get(0).replaceAll("(?m)^ *> ?", ""), top, true, context); - context.pushToken(new BlockquoteEndToken()); - continue; - } - } - { Extension.LexResult result = null; for (Extension extension : options.getExtensions()) { @@ -185,6 +173,18 @@ protected void token(String src, boolean top, boolean bq, LexerContext context){ } } + // blockquote + { + List cap = rules.get("blockquote").exec(src); + if(!cap.isEmpty()){ + src = src.substring(cap.get(0).length()); + context.pushToken(new BlockquoteStartToken()); + token(cap.get(0).replaceAll("(?m)^ *> ?", ""), top, true, context); + context.pushToken(new BlockquoteEndToken()); + continue; + } + } + // list { List cap = rules.get("list").exec(src); diff --git a/src/main/java/io/github/gitbucket/markedj/Options.java b/src/main/java/io/github/gitbucket/markedj/Options.java index cb10bc2..a7e8e98 100644 --- a/src/main/java/io/github/gitbucket/markedj/Options.java +++ b/src/main/java/io/github/gitbucket/markedj/Options.java @@ -19,7 +19,7 @@ public class Options { "colgroup", "dd", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small", "span", "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", - "ul", "input", "del", "hr") + "ul", "input", "del", "hr", "svg", "path") .addAttributes("a", "href", "title") .addProtocols("a", "href", "http", "https", "mailto", "ftp", "#") .addAttributes("blockquote", "cite") @@ -34,7 +34,10 @@ public class Options { .addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope", "width") .addAttributes("ul", "type") .addAttributes("input", "type", "checked", "name", "value", "disabled") - .addAttributes(":all", "id", "class", "style"); + .addAttributes("svg", "class", "viewBox", "version", "width", "height", "aria-hidden") + .addAttributes("path", "d") + .addAttributes(":all", "id", "class", "style") + ; private List extensions = new ArrayList<>(); diff --git a/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/DefaultGFMAlertRenderer.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/DefaultGFMAlertRenderer.java new file mode 100644 index 0000000..623b918 --- /dev/null +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/DefaultGFMAlertRenderer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024 GitBucket. + * + * 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. + */ +package io.github.gitbucket.markedj.extension.gfm.alert; + +import java.util.Locale; + +/** + * + * @author t.marx + */ +public class DefaultGFMAlertRenderer implements GFMAlertRenderer { + + @Override + public String render(GFMAlertOptions options, String message, GFMAlerts.Alert alert) { + if (!message.startsWith("

")) { + message = String.format("

%s

", message); + } + + return String.format("

%s

\n%s
", + alert.name().toLowerCase(Locale.ENGLISH), + options.getTitle(alert), + message + ); + } + +} diff --git a/src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationEndToken.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertEndToken.java similarity index 80% rename from src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationEndToken.java rename to src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertEndToken.java index c3e8c8f..60f215a 100644 --- a/src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationEndToken.java +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertEndToken.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.github.gitbucket.markedj.extension.notification; +package io.github.gitbucket.markedj.extension.gfm.alert; import io.github.gitbucket.markedj.token.Token; @@ -21,9 +21,12 @@ * * @author t.marx */ -public class NotificationEndToken implements Token { +public class GFMAlertEndToken implements Token { + + public static String TYPE = "GFMAlertEndToken"; + @Override public String getType() { - return "NotificationEndToken"; + return TYPE; } } diff --git a/src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationExtension.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertExtension.java similarity index 51% rename from src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationExtension.java rename to src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertExtension.java index de322c4..d05e80f 100644 --- a/src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationExtension.java +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertExtension.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.github.gitbucket.markedj.extension.notification; +package io.github.gitbucket.markedj.extension.gfm.alert; import io.github.gitbucket.markedj.Lexer; import io.github.gitbucket.markedj.Parser; @@ -22,51 +22,60 @@ import io.github.gitbucket.markedj.rule.FindFirstRule; import io.github.gitbucket.markedj.rule.Rule; import io.github.gitbucket.markedj.token.Token; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * * @author t.marx */ -public class NotificationExtension implements Extension { +public class GFMAlertExtension implements Extension { - public static String BLOCK_NOTIFICATION = "^((?:(!([xv!]?))[^\n]*(?!^!)\n?)+)"; + public static String EXPRESSION = "(?s)(?m)\\A^> \\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\](.+?)(^\n|\\Z)"; - private Rule notificationRule() { - return new FindFirstRule(BLOCK_NOTIFICATION); - } + private static final Rule RULE = new FindFirstRule(EXPRESSION); + + private GFMAlertRenderer renderer = new DefaultGFMAlertRenderer(); + + private GFMAlertOptions options; + public GFMAlertExtension () { + this(new GFMAlertOptions()); + } + + public GFMAlertExtension (GFMAlertOptions options) { + this.options = options; + } + + public void setRenderer (GFMAlertRenderer renderer) { + this.renderer = renderer; + } + + public void setOptions (GFMAlertOptions options) { + this.options = options; + } + + @Override public LexResult lex(String source, final Lexer.LexerContext context, final TokenConsumer consumer) { - List cap = notificationRule().exec(source); + List cap = RULE.exec(source); boolean tokenFound = false; if (!cap.isEmpty()) { // we have detected several contiguous lines of notifications // ensure that all are of same kind String allNotificationsLines = cap.get(0); + + String content = cap.get(2); + + content = content.replaceAll("(?m)^ *> ?", ""); - // if other kind of notifications lines are detected - // let's split them so that they are handled separately - String findOtherLinesPattern = "(?m)^(!" + Notifications.exceptGivenNotificationClass(cap.get(3)) + " .*)"; - Matcher otherLinesMatcher = Pattern.compile(findOtherLinesPattern).matcher(cap.get(1)); - - if (otherLinesMatcher.find()) { - String otherLinesSeparated = otherLinesMatcher.replaceAll("\n$1\n"); - - // change the source to parse - // replace all the notifications lines with separated notifications lines - // and reparse the string - source = otherLinesSeparated + source.substring(allNotificationsLines.length()); - } else { - source = source.substring(allNotificationsLines.length()); - context.pushToken(new NotificationStartToken(cap.get(3))); - consumer.token(allNotificationsLines.replaceAll("(?m)^" + cap.get(2) + "[ ]?", ""), false, false, context); - context.pushToken(new NotificationEndToken()); - } + source = source.substring(allNotificationsLines.length()); + context.pushToken(new GFMAlertStartToken(cap.get(1))); + consumer.token(content, false, false, context); + context.pushToken(new GFMAlertEndToken()); tokenFound = true; } @@ -75,16 +84,16 @@ public LexResult lex(String source, final Lexer.LexerContext context, final Toke @Override public boolean handlesToken(String token) { - return NotificationStartToken.TYPE.equals(token); + return GFMAlertStartToken.TYPE.equals(token); } @Override public String parse(Parser.ParserContext context, Function tok) { - NotificationStartToken t = (NotificationStartToken) context.currentToken(); + GFMAlertStartToken t = (GFMAlertStartToken) context.currentToken(); StringBuilder body = new StringBuilder(); while (true) { Token n = context.nextToken(); - if (n == null || n.getType().equals("NotificationEndToken")) { + if (n == null || n.getType().equals(GFMAlertEndToken.TYPE)) { break; } body.append(tok.apply(context)); @@ -92,7 +101,7 @@ public String parse(Parser.ParserContext context, Function\n%s
\n", notification.name().toLowerCase(Locale.ENGLISH), info); + private String render(String message, GFMAlerts.Alert alert) { + return renderer.render(options, message, alert); } } diff --git a/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertOptions.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertOptions.java new file mode 100644 index 0000000..2844e21 --- /dev/null +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertOptions.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 GitBucket. + * + * 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. + */ +package io.github.gitbucket.markedj.extension.gfm.alert; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author t.marx + */ +public class GFMAlertOptions { + + private final Map titles = new HashMap<>(); + + /** + * Creates the options with default titles. + */ + public GFMAlertOptions () { + titles.put(GFMAlerts.Alert.TIP, "Tip"); + titles.put(GFMAlerts.Alert.NOTE, "Note"); + titles.put(GFMAlerts.Alert.IMPORTANT, "Important"); + titles.put(GFMAlerts.Alert.WARNING, "Warning"); + titles.put(GFMAlerts.Alert.CAUTION, "Caution"); + } + + public String getTitle (GFMAlerts.Alert alert) { + return titles.get(alert); + } + + public void setTitle (GFMAlerts.Alert alert, String title) { + titles.put(alert, title); + } + +} diff --git a/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertRenderer.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertRenderer.java new file mode 100644 index 0000000..62da109 --- /dev/null +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertRenderer.java @@ -0,0 +1,25 @@ +/* + * Copyright 2024 GitBucket. + * + * 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. + */ +package io.github.gitbucket.markedj.extension.gfm.alert; + + +/** + * + * @author t.marx + */ +public interface GFMAlertRenderer { + String render (final GFMAlertOptions options, final String message, GFMAlerts.Alert alert); +} diff --git a/src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationStartToken.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertStartToken.java similarity index 64% rename from src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationStartToken.java rename to src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertStartToken.java index bc8be7f..56fb787 100644 --- a/src/main/java/io/github/gitbucket/markedj/extension/notification/NotificationStartToken.java +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlertStartToken.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.github.gitbucket.markedj.extension.notification; +package io.github.gitbucket.markedj.extension.gfm.alert; import io.github.gitbucket.markedj.token.Token; @@ -21,13 +21,13 @@ * * @author t.marx */ -public class NotificationStartToken implements Token { - protected static String TYPE = "NotificationStartToken"; +public class GFMAlertStartToken implements Token { + protected static String TYPE = "GFMAlertStartToken"; - private Notifications.Notification notification; + private GFMAlerts.Alert alert; - public NotificationStartToken(String type) { - this.notification = Notifications.Notification.fromString(type); + public GFMAlertStartToken(String type) { + this.alert = GFMAlerts.Alert.fromString(type); } @Override @@ -35,7 +35,7 @@ public String getType() { return TYPE; } - public Notifications.Notification getNotification() { - return notification; + public GFMAlerts.Alert getNotification() { + return alert; } } diff --git a/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlerts.java b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlerts.java new file mode 100644 index 0000000..b5408f3 --- /dev/null +++ b/src/main/java/io/github/gitbucket/markedj/extension/gfm/alert/GFMAlerts.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 GitBucket. + * + * 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. + */ +package io.github.gitbucket.markedj.extension.gfm.alert; + +/** + * + * @author t.marx + */ +public class GFMAlerts { + + public enum Alert { + NOTE, TIP, IMPORTANT, WARNING, CAUTION; + + public static Alert fromString(String s) { + switch (s) { + case "TIP": + return Alert.TIP; + case "IMPORTANT": + return Alert.IMPORTANT; + case "WARNING": + return Alert.WARNING; + case "CAUTION": + return Alert.CAUTION; + default: + return Alert.NOTE; + } + } + } +} diff --git a/src/main/java/io/github/gitbucket/markedj/extension/notification/Notifications.java b/src/main/java/io/github/gitbucket/markedj/extension/notification/Notifications.java deleted file mode 100644 index f1fbedf..0000000 --- a/src/main/java/io/github/gitbucket/markedj/extension/notification/Notifications.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 GitBucket. - * - * 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. - */ -package io.github.gitbucket.markedj.extension.notification; - -/** - * - * @author t.marx - */ -public class Notifications { - public static String exceptGivenNotificationClass(String notificationClassCharacter) { - switch (notificationClassCharacter) { - case "": - return "[xv!]"; - case "x": - return "[v!]?"; - case "v": - return "[x!]?"; - case "!": - return "[xv]?"; - } - throw new IllegalArgumentException("unknown character [" + notificationClassCharacter+ "] to define a notification charcater class"); - } - - public enum Notification { - INFO, SUCCESS, WARNING, ERROR; - - public static Notification fromString(String s) { - switch (s) { - case "x": - return Notification.ERROR; - case "!": - return Notification.WARNING; - case "v": - return Notification.SUCCESS; - default: - return Notification.INFO; - } - } - } -} diff --git a/src/test/java/io/github/gitbucket/markedj/GFMAlertsTest.java b/src/test/java/io/github/gitbucket/markedj/GFMAlertsTest.java new file mode 100644 index 0000000..1f3daef --- /dev/null +++ b/src/test/java/io/github/gitbucket/markedj/GFMAlertsTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2024 GitBucket. + * + * 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. + */ +package io.github.gitbucket.markedj; + +import static io.github.gitbucket.markedj.Resources.loadResourceAsString; +import io.github.gitbucket.markedj.extension.gfm.alert.GFMAlertExtension; +import io.github.gitbucket.markedj.extension.gfm.alert.GFMAlertOptions; +import io.github.gitbucket.markedj.extension.gfm.alert.GFMAlerts; +import java.util.Locale; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +/** + * + * @author t.marx + */ +public class GFMAlertsTest { + + + private Options createOptions () { + Options options = new Options(); + options.addExtension(new GFMAlertExtension()); + return options; + } + + @Test + public void testNoteAlert() throws Exception { + String md = loadResourceAsString("gfm/alerts/note.md"); + String result = Marked.marked(md, createOptions()); + String expect = loadResourceAsString("gfm/alerts/note.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testTipAlert() throws Exception { + String md = loadResourceAsString("gfm/alerts/tip.md"); + String result = Marked.marked(md, createOptions()); + String expect = loadResourceAsString("gfm/alerts/tip.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testImportantAlert() throws Exception { + String md = loadResourceAsString("gfm/alerts/important.md"); + String result = Marked.marked(md, createOptions()); + String expect = loadResourceAsString("gfm/alerts/important.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testCautionAlert() throws Exception { + String md = loadResourceAsString("gfm/alerts/caution.md"); + String result = Marked.marked(md, createOptions()); + String expect = loadResourceAsString("gfm/alerts/caution.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testWarningAlert() throws Exception { + String md = loadResourceAsString("gfm/alerts/warning.md"); + String result = Marked.marked(md, createOptions()); + String expect = loadResourceAsString("gfm/alerts/warning.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testWithCustomTitle() throws Exception { + String md = loadResourceAsString("gfm/alerts/warning.md"); + + Options options = new Options(); + + + GFMAlertOptions alertOptions = new GFMAlertOptions(); + alertOptions.setTitle(GFMAlerts.Alert.WARNING, "Attention!!!"); + final GFMAlertExtension gfmAlertExtension = new GFMAlertExtension(alertOptions); + options.addExtension(gfmAlertExtension); + + String result = Marked.marked(md, options); + String expect = loadResourceAsString("gfm/alerts/warning_custom_title.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testWithCustomRenderer() throws Exception { + String md = loadResourceAsString("gfm/alerts/warning.md"); + + Options options = new Options(); + final GFMAlertExtension gfmAlertExtension = new GFMAlertExtension(); + gfmAlertExtension.setRenderer((alertOptions, message, alert) -> { + return String.format("

%s

\n%s
", + alert.name().toLowerCase(Locale.ENGLISH), + alertOptions.getTitle(alert), + message + ); + }); + options.addExtension(gfmAlertExtension); + + String result = Marked.marked(md, options); + String expect = loadResourceAsString("gfm/alerts/warning_custom_renderer.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testWithParagraphBeforeAndAfter() throws Exception { + String md = loadResourceAsString("gfm/alerts/testWithParagraphBeforeAndAfter.md"); + + Options options = new Options(); + final GFMAlertExtension gfmAlertExtension = new GFMAlertExtension(); + options.addExtension(gfmAlertExtension); + + String result = Marked.marked(md, options); + String expect = loadResourceAsString("gfm/alerts/testWithParagraphBeforeAndAfter.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } + + @Test + public void testWithMultipleAlerts() throws Exception { + String md = loadResourceAsString("gfm/alerts/testWithMultipleAlerts.md"); + + Options options = new Options(); + final GFMAlertExtension gfmAlertExtension = new GFMAlertExtension(); + options.addExtension(gfmAlertExtension); + + String result = Marked.marked(md, options); + String expect = loadResourceAsString("gfm/alerts/testWithMultipleAlerts.html"); + Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); + } +} diff --git a/src/test/java/io/github/gitbucket/markedj/NotificationsTest.java b/src/test/java/io/github/gitbucket/markedj/NotificationsTest.java deleted file mode 100644 index 8223fd7..0000000 --- a/src/test/java/io/github/gitbucket/markedj/NotificationsTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package io.github.gitbucket.markedj; - -import static io.github.gitbucket.markedj.Resources.loadResourceAsString; -import io.github.gitbucket.markedj.extension.notification.NotificationExtension; -import org.assertj.core.api.Assertions; - -import org.junit.Test; - -public class NotificationsTest { - - private Options createOptions () { - Options options = new Options(); - options.addExtension(new NotificationExtension()); - return options; - } - - @Test - public void testInfoNotification() throws Exception { - String md = loadResourceAsString("notifications/info.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/info.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testSuccessNotification() throws Exception { - String md = loadResourceAsString("notifications/success.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/success.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testWarningNotification() throws Exception { - String md = loadResourceAsString("notifications/warning.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/warning.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testErrorNotification() throws Exception { - String md = loadResourceAsString("notifications/error.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/error.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testMultipleNotifications1() throws Exception { - String md = loadResourceAsString("notifications/multiple_notifications_1.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/multiple_notifications_1.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testMultipleNotifications2() throws Exception { - String md = loadResourceAsString("notifications/multiple_notifications_2.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/multiple_notifications_2.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testMultipleNotifications3() throws Exception { - String md = loadResourceAsString("notifications/multiple_notifications_3.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/multiple_notifications_3.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testMultipleNotificationsWithTypeChange() throws Exception { - String md = loadResourceAsString("notifications/multiple_notifications_type_change.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/multiple_notifications_type_change.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } - - @Test - public void testEmbeddedNotifications() throws Exception { - String md = loadResourceAsString("notifications/embedded_notifications.md"); - String result = Marked.marked(md, createOptions()); - String expect = loadResourceAsString("notifications/embedded_notifications.html"); - Assertions.assertThat(result).isEqualToIgnoringWhitespace(expect); - } -} diff --git a/src/test/resources/gfm/alerts/caution.html b/src/test/resources/gfm/alerts/caution.html new file mode 100644 index 0000000..8df52ee --- /dev/null +++ b/src/test/resources/gfm/alerts/caution.html @@ -0,0 +1,4 @@ +
+

Caution

+

Advises about risks or negative outcomes of certain actions.

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/caution.md b/src/test/resources/gfm/alerts/caution.md new file mode 100644 index 0000000..425f438 --- /dev/null +++ b/src/test/resources/gfm/alerts/caution.md @@ -0,0 +1,2 @@ +> [!CAUTION] +> Advises about risks or negative outcomes of certain actions. \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/important.html b/src/test/resources/gfm/alerts/important.html new file mode 100644 index 0000000..96f6d83 --- /dev/null +++ b/src/test/resources/gfm/alerts/important.html @@ -0,0 +1,4 @@ +
+

Important

+

Key information users need to know to achieve their goal.

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/important.md b/src/test/resources/gfm/alerts/important.md new file mode 100644 index 0000000..81f711d --- /dev/null +++ b/src/test/resources/gfm/alerts/important.md @@ -0,0 +1,2 @@ +> [!IMPORTANT] +> Key information users need to know to achieve their goal. \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/note.html b/src/test/resources/gfm/alerts/note.html new file mode 100644 index 0000000..9a0614e --- /dev/null +++ b/src/test/resources/gfm/alerts/note.html @@ -0,0 +1,4 @@ +
+

Note

+

Useful information that users should know, even when skimming content.

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/note.md b/src/test/resources/gfm/alerts/note.md new file mode 100644 index 0000000..c2cc523 --- /dev/null +++ b/src/test/resources/gfm/alerts/note.md @@ -0,0 +1,3 @@ +> [!NOTE] +> Useful information that users should know, +> even when skimming content. \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/testWithMultipleAlerts.html b/src/test/resources/gfm/alerts/testWithMultipleAlerts.html new file mode 100644 index 0000000..16f7b0e --- /dev/null +++ b/src/test/resources/gfm/alerts/testWithMultipleAlerts.html @@ -0,0 +1,8 @@ +
+

Note

+

Useful information that users should know, even when skimming content.

+
+
+

Tip

+

A tip!

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/testWithMultipleAlerts.md b/src/test/resources/gfm/alerts/testWithMultipleAlerts.md new file mode 100644 index 0000000..514ab4b --- /dev/null +++ b/src/test/resources/gfm/alerts/testWithMultipleAlerts.md @@ -0,0 +1,6 @@ +> [!NOTE] +> Useful information that users should know, +> even when skimming content. + +> [!TIP] +> A tip! \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.html b/src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.html new file mode 100644 index 0000000..8c522a0 --- /dev/null +++ b/src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.html @@ -0,0 +1,6 @@ +

A simple paragraph before.

+
+

Note

+

Useful information that users should know, even when skimming content.

+
+

Another paragraph after.

\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.md b/src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.md new file mode 100644 index 0000000..9b2a11b --- /dev/null +++ b/src/test/resources/gfm/alerts/testWithParagraphBeforeAndAfter.md @@ -0,0 +1,7 @@ +A simple paragraph before. + +> [!NOTE] +> Useful information that users should know, +> even when skimming content. + +Another paragraph after. \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/tip.html b/src/test/resources/gfm/alerts/tip.html new file mode 100644 index 0000000..509561f --- /dev/null +++ b/src/test/resources/gfm/alerts/tip.html @@ -0,0 +1,4 @@ +
+

Tip

+

Helpful advice for doing things better or more easily.

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/tip.md b/src/test/resources/gfm/alerts/tip.md new file mode 100644 index 0000000..bbec8a1 --- /dev/null +++ b/src/test/resources/gfm/alerts/tip.md @@ -0,0 +1,2 @@ +> [!TIP] +> Helpful advice for doing things better or more easily. \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/warning.html b/src/test/resources/gfm/alerts/warning.html new file mode 100644 index 0000000..9921bfd --- /dev/null +++ b/src/test/resources/gfm/alerts/warning.html @@ -0,0 +1,4 @@ +
+

Warning

+

Urgent info that needs immediate user attention to avoid problems.

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/warning.md b/src/test/resources/gfm/alerts/warning.md new file mode 100644 index 0000000..76301ba --- /dev/null +++ b/src/test/resources/gfm/alerts/warning.md @@ -0,0 +1,2 @@ +> [!WARNING] +> Urgent info that needs immediate user attention to avoid problems. \ No newline at end of file diff --git a/src/test/resources/gfm/alerts/warning_custom_renderer.html b/src/test/resources/gfm/alerts/warning_custom_renderer.html new file mode 100644 index 0000000..0863eab --- /dev/null +++ b/src/test/resources/gfm/alerts/warning_custom_renderer.html @@ -0,0 +1,4 @@ +
+

Warning

+

Urgent info that needs immediate user attention to avoid problems.

+
\ No newline at end of file diff --git a/src/test/resources/gfm/alerts/warning_custom_title.html b/src/test/resources/gfm/alerts/warning_custom_title.html new file mode 100644 index 0000000..707581c --- /dev/null +++ b/src/test/resources/gfm/alerts/warning_custom_title.html @@ -0,0 +1,4 @@ +
+

Attention!!!

+

Urgent info that needs immediate user attention to avoid problems.

+
\ No newline at end of file diff --git a/src/test/resources/notifications/embedded_notifications.html b/src/test/resources/notifications/embedded_notifications.html deleted file mode 100644 index 67dacf1..0000000 --- a/src/test/resources/notifications/embedded_notifications.html +++ /dev/null @@ -1,8 +0,0 @@ -
-

Info message. -Written using multiple lines.

-
-

Embedding a warning

-
-

Initial info message continues afterwards.

-
diff --git a/src/test/resources/notifications/embedded_notifications.md b/src/test/resources/notifications/embedded_notifications.md deleted file mode 100644 index c42e29f..0000000 --- a/src/test/resources/notifications/embedded_notifications.md +++ /dev/null @@ -1,6 +0,0 @@ -! Info message. -! Written using multiple lines. -! -! !! Embedding a warning -! -! Initial info message continues afterwards. diff --git a/src/test/resources/notifications/error.html b/src/test/resources/notifications/error.html deleted file mode 100644 index 6dcb069..0000000 --- a/src/test/resources/notifications/error.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

This is an error message -That spans over several lines

-
diff --git a/src/test/resources/notifications/error.md b/src/test/resources/notifications/error.md deleted file mode 100644 index 67d156c..0000000 --- a/src/test/resources/notifications/error.md +++ /dev/null @@ -1,2 +0,0 @@ -!x This is an error message -!x That spans over several lines \ No newline at end of file diff --git a/src/test/resources/notifications/info.html b/src/test/resources/notifications/info.html deleted file mode 100644 index 15ca4e6..0000000 --- a/src/test/resources/notifications/info.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

This is an info message -That spans over several lines

-
diff --git a/src/test/resources/notifications/info.md b/src/test/resources/notifications/info.md deleted file mode 100644 index be22ac8..0000000 --- a/src/test/resources/notifications/info.md +++ /dev/null @@ -1,2 +0,0 @@ -! This is an info message -! That spans over several lines \ No newline at end of file diff --git a/src/test/resources/notifications/multiple_notifications_1.html b/src/test/resources/notifications/multiple_notifications_1.html deleted file mode 100644 index 17f1358..0000000 --- a/src/test/resources/notifications/multiple_notifications_1.html +++ /dev/null @@ -1,9 +0,0 @@ -
-

This is info message 1

-
-
-

This is info message 2

-
-
-

This is info message 3

-
diff --git a/src/test/resources/notifications/multiple_notifications_1.md b/src/test/resources/notifications/multiple_notifications_1.md deleted file mode 100644 index 58017f2..0000000 --- a/src/test/resources/notifications/multiple_notifications_1.md +++ /dev/null @@ -1,5 +0,0 @@ -! This is info message 1 - -! This is info message 2 - -! This is info message 3 diff --git a/src/test/resources/notifications/multiple_notifications_2.html b/src/test/resources/notifications/multiple_notifications_2.html deleted file mode 100644 index 9c82bc6..0000000 --- a/src/test/resources/notifications/multiple_notifications_2.html +++ /dev/null @@ -1,5 +0,0 @@ -
-

This is info message 1 -This is info message 2 -This is info message 3

-
diff --git a/src/test/resources/notifications/multiple_notifications_2.md b/src/test/resources/notifications/multiple_notifications_2.md deleted file mode 100644 index a80f636..0000000 --- a/src/test/resources/notifications/multiple_notifications_2.md +++ /dev/null @@ -1,4 +0,0 @@ -! This is info message 1 -! This is info message 2 -! This is info message 3 - diff --git a/src/test/resources/notifications/multiple_notifications_3.html b/src/test/resources/notifications/multiple_notifications_3.html deleted file mode 100644 index e9bc640..0000000 --- a/src/test/resources/notifications/multiple_notifications_3.html +++ /dev/null @@ -1,5 +0,0 @@ -
-

This is info message 1 -This is info message 2

-

This is info message 3

-
diff --git a/src/test/resources/notifications/multiple_notifications_3.md b/src/test/resources/notifications/multiple_notifications_3.md deleted file mode 100644 index f227777..0000000 --- a/src/test/resources/notifications/multiple_notifications_3.md +++ /dev/null @@ -1,5 +0,0 @@ -! This is info message 1 -! This is info message 2 -! -! This is info message 3 - diff --git a/src/test/resources/notifications/multiple_notifications_type_change.html b/src/test/resources/notifications/multiple_notifications_type_change.html deleted file mode 100644 index 35e6566..0000000 --- a/src/test/resources/notifications/multiple_notifications_type_change.html +++ /dev/null @@ -1,11 +0,0 @@ -
-

line 1 - line 2

-
-
-

line 3

-
-
-

line 4 - line 5

-
diff --git a/src/test/resources/notifications/multiple_notifications_type_change.md b/src/test/resources/notifications/multiple_notifications_type_change.md deleted file mode 100644 index 11656ba..0000000 --- a/src/test/resources/notifications/multiple_notifications_type_change.md +++ /dev/null @@ -1,6 +0,0 @@ -!x line 1 -!x line 2 - -! line 3 -!x line 4 -!x line 5 diff --git a/src/test/resources/notifications/success.html b/src/test/resources/notifications/success.html deleted file mode 100644 index d297c56..0000000 --- a/src/test/resources/notifications/success.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

This is a success message -That spans over several lines

-
diff --git a/src/test/resources/notifications/success.md b/src/test/resources/notifications/success.md deleted file mode 100644 index f2979c0..0000000 --- a/src/test/resources/notifications/success.md +++ /dev/null @@ -1,2 +0,0 @@ -!v This is a success message -!v That spans over several lines \ No newline at end of file diff --git a/src/test/resources/notifications/warning.html b/src/test/resources/notifications/warning.html deleted file mode 100644 index e0c0bb4..0000000 --- a/src/test/resources/notifications/warning.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

This is a warning message -That spans over several lines

-
diff --git a/src/test/resources/notifications/warning.md b/src/test/resources/notifications/warning.md deleted file mode 100644 index b10aab1..0000000 --- a/src/test/resources/notifications/warning.md +++ /dev/null @@ -1,2 +0,0 @@ -!! This is a warning message -!! That spans over several lines \ No newline at end of file