diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java
index 6f5d8bf6c23a8..5ef48f8b6fd30 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java
@@ -52,6 +52,7 @@ final class JavaDocParser {
private static final String ORDERED_LIST_NODE = "ol";
private static final String SUPER_SCRIPT_NODE = "sup";
private static final String UN_ORDERED_LIST_NODE = "ul";
+ private static final String PREFORMATED_NODE = "pre";
private static final String BIG_ASCIDOC_STYLE = "[.big]";
private static final String LINK_ATTRIBUTE_FORMAT = "[%s]";
@@ -62,6 +63,8 @@ final class JavaDocParser {
private static final String UNORDERED_LIST_ITEM_ASCIDOC_STYLE = " - ";
private static final String UNDERLINE_ASCIDOC_STYLE = "[.underline]";
private static final String LINE_THROUGH_ASCIDOC_STYLE = "[.line-through]";
+ private static final String HARD_LINE_BREAK_ASCIDOC_STYLE = " +\n";
+ private static final String CODE_BLOCK_ASCIDOC_STYLE = "```";
private final boolean inlineMacroMode;
@@ -185,25 +188,37 @@ private String htmlJavadocToAsciidoc(JavadocDescription javadocDescription) {
}
}
- return sb.toString().trim();
+ return trim(sb);
}
private void appendHtml(StringBuilder sb, Node node) {
for (Node childNode : node.childNodes()) {
switch (childNode.nodeName()) {
case PARAGRAPH_NODE:
- sb.append(NEW_LINE);
+ newLine(sb);
+ newLine(sb);
appendHtml(sb, childNode);
break;
+ case PREFORMATED_NODE:
+ newLine(sb);
+ newLine(sb);
+ sb.append(CODE_BLOCK_ASCIDOC_STYLE);
+ newLine(sb);
+ for (Node grandChildNode : childNode.childNodes()) {
+ sb.append(grandChildNode.toString());
+ }
+ sb.append(CODE_BLOCK_ASCIDOC_STYLE);
+ break;
case ORDERED_LIST_NODE:
case UN_ORDERED_LIST_NODE:
+ newLine(sb);
appendHtml(sb, childNode);
break;
case LIST_ITEM_NODE:
final String marker = childNode.parent().nodeName().equals(ORDERED_LIST_NODE)
? ORDERED_LIST_ITEM_ASCIDOC_STYLE
: UNORDERED_LIST_ITEM_ASCIDOC_STYLE;
- sb.append(NEW_LINE);
+ newLine(sb);
sb.append(marker);
appendHtml(sb, childNode);
break;
@@ -213,7 +228,7 @@ private void appendHtml(StringBuilder sb, Node node) {
sb.append(link);
final StringBuilder caption = new StringBuilder();
appendHtml(caption, childNode);
- sb.append(String.format(LINK_ATTRIBUTE_FORMAT, caption.toString().trim()));
+ sb.append(String.format(LINK_ATTRIBUTE_FORMAT, trim(caption)));
break;
case CODE_NODE:
sb.append(BACKTICK);
@@ -269,7 +284,7 @@ private void appendHtml(StringBuilder sb, Node node) {
sb.append(HASH);
break;
case NEW_LINE_NODE:
- sb.append(NEW_LINE);
+ sb.append(HARD_LINE_BREAK_ASCIDOC_STYLE);
break;
case TEXT_NODE:
String text = ((TextNode) childNode).text();
@@ -295,6 +310,66 @@ private void appendHtml(StringBuilder sb, Node node) {
}
}
+ /**
+ * Trim the content of the given {@link StringBuilder} holding also AsciiDoc had line break {@code " +\n"}
+ * for whitespace in addition to characters <= {@code ' '}.
+ *
+ * @param sb the {@link StringBuilder} to trim
+ * @return the trimmed content of the given {@link StringBuilder}
+ */
+ static String trim(StringBuilder sb) {
+ int length = sb.length();
+ int offset = 0;
+ while (offset < length) {
+ final char ch = sb.charAt(offset);
+ if (ch == ' '
+ && offset + 2 < length
+ && sb.charAt(offset + 1) == '+'
+ && sb.charAt(offset + 2) == '\n') {
+ /* Space followed by + and newline is AsciiDoc hard break that we consider whitespace */
+ offset += 3;
+ continue;
+ } else if (ch > ' ') {
+ /* Non-whitespace as defined by String.trim() */
+ break;
+ }
+ offset++;
+ }
+ if (offset > 0) {
+ sb.delete(0, offset);
+ }
+ if (sb.length() > 0) {
+ offset = sb.length() - 1;
+ while (offset >= 0) {
+ final char ch = sb.charAt(offset);
+ if (ch == '\n'
+ && offset - 2 >= 0
+ && sb.charAt(offset - 1) == '+'
+ && sb.charAt(offset - 2) == ' ') {
+ /* Space followed by + is AsciiDoc hard break that we consider whitespace */
+ offset -= 3;
+ continue;
+ } else if (ch > ' ') {
+ /* Non-whitespace as defined by String.trim() */
+ break;
+ }
+ offset--;
+ }
+ if (offset < sb.length() - 1) {
+ sb.setLength(offset + 1);
+ }
+ }
+ return sb.toString();
+ }
+
+ private static StringBuilder newLine(StringBuilder sb) {
+ /* Trim trailing spaces and tabs at the end of line */
+ while (sb.length() > 0 && " \t".indexOf(sb.charAt(sb.length() - 1)) >= 0) {
+ sb.setLength(sb.length() - 1);
+ }
+ return sb.append(NEW_LINE);
+ }
+
private StringBuilder appendEscapedAsciiDoc(StringBuilder sb, String text) {
boolean escaping = false;
for (int i = 0; i < text.length(); i++) {
diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java
index 5410b7f7bdc91..34f59f195b853 100644
--- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java
+++ b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java
@@ -28,7 +28,7 @@ public void parseNullJavaDoc() {
@Test
public void removeParagraphIndentation() {
String parsed = parser.parseConfigDescription("First paragraph
Second Paragraph");
- assertEquals("First paragraph\n\nSecond Paragraph", parsed);
+ assertEquals("First paragraph +\n +\nSecond Paragraph", parsed);
}
@Test
@@ -50,13 +50,13 @@ public void parseSimpleJavaDoc() {
@Test
public void parseJavaDocWithParagraph() {
String javaDoc = "hello
world
"; - String expectedOutput = "hello\nworld"; + String expectedOutput = "hello\n\nworld"; String parsed = parser.parseConfigDescription(javaDoc); assertEquals(expectedOutput, parsed); javaDoc = "hello worldbonjour
le monde
"; - expectedOutput = "hello world\nbonjour \nle monde"; + expectedOutput = "hello world\n\nbonjour\n\nle monde"; parsed = parser.parseConfigDescription(javaDoc); assertEquals(expectedOutput, parsed); @@ -118,21 +118,6 @@ public void parseJavaDocWithStyles() { assertEquals(expectedOutput, parsed); } - @Test - public void parseJavaDocWithUlTags() { - String javaDoc = "hello\nfoo\nbar\n")); + + // TODO + // assertEquals("Example:\n\n```\nfoo\nbar\n```", + // parser.parseConfigDescription("Example:\n\n
{@code\nfoo\nbar\n}")); + } + @Test public void asciidoc() { String asciidoc = "== My Asciidoc\n" + @@ -308,4 +302,25 @@ public void escapeBrackets(String ch) { assertEquals(expected, actual); } + @Test + void trim() { + assertEquals("+ \nfoo", JavaDocParser.trim(new StringBuilder("+ \nfoo"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder(" +"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder(" +\nfoo"))); + assertEquals("foo +", JavaDocParser.trim(new StringBuilder("foo +"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder("foo"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder("+ \n"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder(" +\n+ \n"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder(" \n\tfoo"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder("foo \n\t"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder(" \n\tfoo \n\t"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(""))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" \n\t"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder(" +"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n +\n"))); + assertEquals("foo +\nbar", JavaDocParser.trim(new StringBuilder(" foo +\nbar +\n"))); + } + }