aboutsummaryrefslogtreecommitdiffstats
path: root/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java')
-rw-r--r--javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java152
1 files changed, 152 insertions, 0 deletions
diff --git a/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java b/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java
new file mode 100644
index 000000000..bbe9797e2
--- /dev/null
+++ b/javaparser-core/src/main/java/com/github/javaparser/JavadocParser.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2016 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+
+package com.github.javaparser;
+
+import com.github.javaparser.ast.comments.JavadocComment;
+import com.github.javaparser.javadoc.Javadoc;
+import com.github.javaparser.javadoc.JavadocBlockTag;
+import com.github.javaparser.javadoc.description.JavadocDescription;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static com.github.javaparser.utils.Utils.*;
+import static com.github.javaparser.utils.Utils.nextWord;
+
+/**
+ * The class responsible for parsing the content of JavadocComments and produce JavadocDocuments.
+ */
+class JavadocParser {
+
+ private static String BLOCK_TAG_PREFIX = "@";
+ private static Pattern BLOCK_PATTERN = Pattern.compile("^" + BLOCK_TAG_PREFIX, Pattern.MULTILINE);
+
+ public static Javadoc parse(JavadocComment comment) {
+ return parse(comment.getContent());
+ }
+
+ public static Javadoc parse(String commentContent) {
+ List<String> cleanLines = cleanLines(normalizeEolInTextBlock(commentContent, EOL));
+ int indexOfFirstBlockTag = cleanLines.stream()
+ .filter(JavadocParser::isABlockLine)
+ .map(cleanLines::indexOf)
+ .findFirst()
+ .orElse(-1);
+ List<String> blockLines;
+ String descriptionText;
+ if (indexOfFirstBlockTag == -1) {
+ descriptionText = trimRight(String.join(EOL, cleanLines));
+ blockLines = Collections.emptyList();
+ } else {
+ descriptionText = trimRight(String.join(EOL, cleanLines.subList(0, indexOfFirstBlockTag)));
+
+ //Combine cleaned lines, but only starting with the first block tag till the end
+ //In this combined string it is easier to handle multiple lines which actually belong together
+ String tagBlock = cleanLines.subList(indexOfFirstBlockTag, cleanLines.size())
+ .stream()
+ .collect(Collectors.joining(EOL));
+
+ //Split up the entire tag back again, considering now that some lines belong to the same block tag.
+ //The pattern splits the block at each new line starting with the '@' symbol, thus the symbol
+ //then needs to be added again so that the block parsers handles everything correctly.
+ blockLines = BLOCK_PATTERN
+ .splitAsStream(tagBlock)
+ .filter(STRING_NOT_EMPTY)
+ .map(s -> BLOCK_TAG_PREFIX + s)
+ .collect(Collectors.toList());
+ }
+ Javadoc document = new Javadoc(JavadocDescription.parseText(descriptionText));
+ blockLines.forEach(l -> document.addBlockTag(parseBlockTag(l)));
+ return document;
+ }
+
+ private static JavadocBlockTag parseBlockTag(String line) {
+ line = line.trim().substring(1);
+ String tagName = nextWord(line);
+ String rest = line.substring(tagName.length()).trim();
+ return new JavadocBlockTag(tagName, rest);
+ }
+
+ private static boolean isABlockLine(String line) {
+ return line.trim().startsWith(BLOCK_TAG_PREFIX);
+ }
+
+ private static String trimRight(String string) {
+ while (!string.isEmpty() && Character.isWhitespace(string.charAt(string.length() - 1))) {
+ string = string.substring(0, string.length() - 1);
+ }
+ return string;
+ }
+
+ private static List<String> cleanLines(String content) {
+ String[] lines = content.split(EOL);
+ List<String> cleanedLines = Arrays.stream(lines).map(l -> {
+ int asteriskIndex = startsWithAsterisk(l);
+ if (asteriskIndex == -1) {
+ return l;
+ } else {
+ // if a line starts with space followed by an asterisk drop to the asterisk
+ // if there is a space immediately after the asterisk drop it also
+ if (l.length() > (asteriskIndex + 1)) {
+
+ char c = l.charAt(asteriskIndex + 1);
+ if (c == ' ' || c == '\t') {
+ return l.substring(asteriskIndex + 2);
+ }
+ }
+ return l.substring(asteriskIndex + 1);
+ }
+ }).collect(Collectors.toList());
+ // lines containing only whitespace are normalized to empty lines
+ cleanedLines = cleanedLines.stream().map(l -> l.trim().isEmpty() ? "" : l).collect(Collectors.toList());
+ // if the first starts with a space, remove it
+ if (!cleanedLines.get(0).isEmpty() && (cleanedLines.get(0).charAt(0) == ' ' || cleanedLines.get(0).charAt(0) == '\t')) {
+ cleanedLines.set(0, cleanedLines.get(0).substring(1));
+ }
+ // drop empty lines at the beginning and at the end
+ while (cleanedLines.size() > 0 && cleanedLines.get(0).trim().isEmpty()) {
+ cleanedLines = cleanedLines.subList(1, cleanedLines.size());
+ }
+ while (cleanedLines.size() > 0 && cleanedLines.get(cleanedLines.size() - 1).trim().isEmpty()) {
+ cleanedLines = cleanedLines.subList(0, cleanedLines.size() - 1);
+ }
+ return cleanedLines;
+ }
+
+ // Visible for testing
+ static int startsWithAsterisk(String line) {
+ if (line.startsWith("*")) {
+ return 0;
+ } else if ((line.startsWith(" ") || line.startsWith("\t")) && line.length() > 1) {
+ int res = startsWithAsterisk(line.substring(1));
+ if (res == -1) {
+ return -1;
+ } else {
+ return 1 + res;
+ }
+ } else {
+ return -1;
+ }
+ }
+}