All Downloads are FREE. Search and download functionalities are using the official Maven repository.

za.co.mip.ablduck.utilities.CommentParser Maven / Gradle / Ivy

There is a newer version: 229
Show newest version
/**
 * Copyright 2017-2018 MIP Holdings
 *
 *  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 za.co.mip.ablduck.utilities;

import org.apache.tools.ant.Task;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import za.co.mip.ablduck.javadoc.Javadoc;

import java.io.IOException;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

public class CommentParser {
    private String comment;
    private String source;
    private Map nestedComments = new HashMap<>();
    private Javadoc javadocParser;
    private Pattern oldCommentDetectPattern = Pattern.compile("^\\s*?\\/\\*\\s*?-+.+$",
            Pattern.MULTILINE);
    private String oldCommentTokenPattern = "(^\\s*?[TOKEN]\\s*?:([\\s\\S]*?))(?:\\n|\\z)*(?:^\\s*?Component\\s*?:|^\\s*?Author\\s*?:|^\\s*?File\\s*?:|^\\s*?Purpose\\s*?:|^\\s*?Syntax\\s*?:|^\\s*?Description\\s*?:|^\\s*?Author\\(s\\)\\s*?:|^\\s*?Created\\s*?:|^\\s*?Notes\\s*?:|^\\s*?@param|^\\s*?@return|^\\s*?## Purpose|^\\s*?## Description|^\\s*?## Notes|\\z)";
    private Map oldCommentPatterns = new HashMap<>();
    private String[] oldCommentTokens = {"File", "Purpose", "Syntax", "Description", "Author(s)",
            "Created", "Notes", "Author", "Component"};

    public CommentParser(Task ablduck) {
        javadocParser = new Javadoc(ablduck);

        for (String token : oldCommentTokens) {
            oldCommentPatterns.put(token,
                    Pattern.compile(
                            oldCommentTokenPattern.replaceFirst(Pattern.quote("[TOKEN]"),
                                    Matcher.quoteReplacement(token.replaceFirst("\\(", "\\\\(")
                                            .replaceFirst("\\)", "\\\\)"))),
                            Pattern.MULTILINE | Pattern.CASE_INSENSITIVE));
        }
    }

    public String markdown(String comment) throws IOException {
        String markdown = "";

        Parser parser = Parser.builder().build();
        Node document = parser.parse(comment);
        HtmlRenderer renderer = HtmlRenderer.builder().build();
        markdown = renderer.render(document);

        return markdown;
    }

    public void trimCommentLines() {

        Integer start = comment.indexOf('\n');
        Integer end = comment.lastIndexOf('\n');

        if (Objects.equals(start, end)) {
            comment = "";
            return;
        }

        if (start != -1 && end != -1) {
            comment = comment.substring(start + 1, end);
        }
        Pattern commentLeadingAstrix = Pattern.compile("^\\s*\\*(?:\\s|)(\\n?|[\\s\\S]+?)",
                Pattern.MULTILINE);
        comment = commentLeadingAstrix.matcher(comment).replaceAll("$1");
    }

    public void generateLinks() {
        List tags = javadocParser.parseComment(comment, source);
        Pattern linkPattern = Pattern.compile("^\\{@link ((?:\\w|\\.|-)+)\\s*(.*)\\}$",
                Pattern.DOTALL);

        String l;
        String linkText;

        for (int i = 0; i < tags.size(); i++) {
            Matcher tag = linkPattern.matcher((String) tags.get(i));

            if (tag.find()) {
                if (!"".equals(tag.group(2)))
                    linkText = tag.group(2).trim();
                else
                    linkText = tag.group(1).trim();
                l = "" + linkText + "";
                comment = comment.replaceFirst(Pattern.quote(tag.group(0)),
                        Matcher.quoteReplacement(l));
            }
        }

    }

    public CommentParseResult parseComment(String com, String src) throws IOException {
        CommentParseResult commentParseResult = new CommentParseResult();
        if (com == null)
            return commentParseResult;

        comment = com;
        source = src;

        Boolean isOldComment = detectOldComments();

        // Trim the comment lines
        trimCommentLines();

        if ("".equals(comment))
            return commentParseResult;

        // Take the internal comments out for javaDoc parser
        protectInternalComments();

        // Generate links
        generateLinks();

        // Deprecated flag
        parseDeprecated(commentParseResult);

        // Internal tag
        parseInternal(commentParseResult);

        // Return tag
        parseReturn(commentParseResult);

        // Parameter tags
        parseParamComments(commentParseResult);

        if (isOldComment) {
            parseOldCommentTokens(commentParseResult);
        } else {
            // Author tag
            parseAuthor(commentParseResult);
        }

        // Put comments back in after javaDoc parser
        returnInternalComments();

        comment = markdown(comment);

        commentParseResult.setComment(comment);

        return commentParseResult;
    }

    public Boolean detectOldComments() {
        Matcher oldComment = oldCommentDetectPattern.matcher(comment);
        return oldComment.find();
    }

    public void parseOldCommentTokens(CommentParseResult commentParseResult) {
        for (String token : oldCommentTokens) {
            getOldCommentTag(token, commentParseResult);
        }
    }

    public void getOldCommentTag(String tag, CommentParseResult commentParseResult) {
        Matcher t = oldCommentPatterns.get(tag).matcher(comment);

        if (t.find()) {
            String match = t.group(2).trim();
            match = match.replaceAll("(?m)^\\s*", "");

            if ("".equals(match)) {
                comment = comment.replaceFirst(Pattern.quote(t.group(1)), "");
            } else {
                switch (tag) {
                    case "Purpose" :
                        comment = comment.replaceFirst(Pattern.quote(t.group(1)),
                                Matcher.quoteReplacement("## Purpose\n" + match));
                        break;
                    case "Notes" :
                        comment = comment.replaceFirst(Pattern.quote(t.group(1)),
                                Matcher.quoteReplacement("## Notes\n" + match));
                        break;
                    case "Description" :
                        comment = comment.replaceFirst(Pattern.quote(t.group(1)),
                                Matcher.quoteReplacement("## Description\n" + match));
                        break;
                    case "Author(s)" :
                    case "Author" :
                        comment = comment.replaceFirst(Pattern.quote(t.group(1)), "");
                        commentParseResult.setAuthor(match);
                        break;
                    default :
                        comment = comment.replaceFirst(Pattern.quote(t.group(1)), "");
                        break;
                }
            }
        }
    }

    public void parseReturn(CommentParseResult commentParseResult) {
        commentParseResult
                .setReturnComment(getValueTag(Pattern.compile("@return\\s+(.*)", Pattern.DOTALL)));
    }

    public void parseAuthor(CommentParseResult commentParseResult) {
        commentParseResult
                .setAuthor(getValueTag(Pattern.compile("@author\\s+(.*)", Pattern.DOTALL)));
    }

    public void parseInternal(CommentParseResult commentParseResult) {
        commentParseResult.setInternal(getBooleanTag(Pattern.compile("@internal")));
    }

    public void parseDeprecated(CommentParseResult commentParseResult) throws IOException {
        Map deprecated = getKeyValueTags(
                Pattern.compile("@deprecated\\s+(.+?)\\s+(.*)", Pattern.DOTALL));

        if (deprecated.size() > 0) {
            commentParseResult.setDeprecatedVersion(deprecated.keySet().iterator().next());
            commentParseResult
                    .setDeprecatedText(deprecated.get(commentParseResult.getDeprecatedVersion()));
        }
    }

    public void parseParamComments(CommentParseResult commentParseResult) throws IOException {
        commentParseResult.setParameterComment(
                getKeyValueTags(Pattern.compile("@param\\s+(.+?)\\s+(.*)", Pattern.DOTALL)));
    }

    public void protectInternalComments() {
        Pattern simpleComment = Pattern.compile("(\\/\\*.*\\*\\/)", Pattern.DOTALL);
        Matcher m = simpleComment.matcher(comment);
        Integer commentCount = 0;
        while (m.find()) {
            String commentTag = "[comment-" + commentCount.toString() + "]";
            nestedComments.put(commentTag, m.group(1));
            comment = comment.replaceFirst(Pattern.quote(m.group(1)),
                    Matcher.quoteReplacement(commentTag));
            commentCount++;
        }
    }

    public void returnInternalComments() {
        for (Map.Entry c : nestedComments.entrySet()) {
            comment = comment.replaceFirst(Pattern.quote(c.getKey()),
                    Matcher.quoteReplacement(c.getValue()));
        }
    }

    public Map getKeyValueTags(Pattern paramRegex) throws IOException {
        Map keyvaluetag = new HashMap<>();

        List tags = javadocParser.parseComment(comment, source);

        for (int i = 0; i < tags.size(); i++) {
            Matcher tag = paramRegex.matcher((String) tags.get(i));
            if (tag.find()) {
                keyvaluetag.put(tag.group(1), markdown(removeLeadingWhitespace(tag.group(2))));

                comment = comment.replaceFirst(Pattern.quote((String) tags.get(i)), "");
            }
        }

        comment = comment.trim();
        return keyvaluetag;
    }

    public String getValueTag(Pattern paramRegex) {
        String value = "";

        List tags = javadocParser.parseComment(comment, source);

        for (int i = 0; i < tags.size(); i++) {
            Matcher tag = paramRegex.matcher((String) tags.get(i));
            if (tag.find()) {
                value = tag.group(1);

                comment = comment.replaceFirst(Pattern.quote((String) tags.get(i)), "");
            }
        }

        comment = comment.trim();
        return value;
    }

    public Boolean getBooleanTag(Pattern paramRegex) {
        Boolean flag = false;

        List tags = javadocParser.parseComment(comment, source);

        for (int i = 0; i < tags.size(); i++) {
            Matcher tag = paramRegex.matcher((String) tags.get(i));
            if (tag.find()) {
                flag = true;

                comment = comment.replaceFirst(Pattern.quote((String) tags.get(i)), "");
            }
        }

        comment = comment.trim();
        return flag;
    }

    public String removeLeadingWhitespace(String text) {
        Pattern whitespace = Pattern.compile("\\n\\s+");

        String trimmed = whitespace.matcher(text).replaceAll("\n");

        return trimmed.trim();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy