org.sonar.plugins.gosu.codenarc.apt.AptParser.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.plugins.gosu.codenarc.apt.AptParser.java

Source

/*
 * Sonar CodeNarc Converter
 * Copyright (C) 2011-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of 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.
 *
 * This program 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.plugins.gosu.codenarc.apt;

import com.google.common.collect.Maps;

import org.apache.commons.lang.StringUtils;
import org.sonar.plugins.gosu.codenarc.RuleParameter;

import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;

public class AptParser {

    private static final String LIST_PREFIX = "* {{";
    private static final String NEW_RULE_PREFIX = "* ";
    private static final String PARAMETER_START_SEPARATOR = "\\*(-)+\\+(-)+\\+(-)+\\+";
    private static final String PARAMETER_SEPARATOR = "\\+((-)+\\+)+";
    private static final String PARAMETER_CONTENT = "(\\|(.)*)+";
    private static final String EXAMPLE_SEPARATOR_1 = "(-)+";
    private static final String EXAMPLE_SEPARATOR_2 = "\\+(-)+";

    public Map<String, AptResult> parse(List<File> files) throws Exception {
        Map<String, AptResult> results = Maps.newHashMap();
        if (!files.isEmpty()) {
            for (File file : files) {
                Map<String, AptResult> parametersByFile = readFile(file);
                mergeParameters(results, parametersByFile);
            }
        }
        return results;
    }

    private Map<String, AptResult> readFile(File file) throws Exception {
        Map<String, AptResult> results = Maps.newHashMap();
        List<String> lines = Files.readAllLines(file.toPath(), Charset.forName("UTF-8"));

        boolean inRule = false;
        boolean inParameters = false;
        boolean inExample = false;
        boolean inDescription = false;
        String currentRule = null;
        AptResult currentResult = null;
        RuleParameter currentParameter = null;
        int[] splits = new int[3];
        for (int index = 0; index < lines.size(); index++) {
            String fullLine = lines.get(index);
            String line = fullLine.trim();
            if (line.startsWith(NEW_RULE_PREFIX) && !line.startsWith(LIST_PREFIX) && inRule) {
                results.put(currentRule, currentResult);
                inRule = false;
                inDescription = false;
                currentRule = null;
                currentResult = null;
            }
            if (!inRule && line.startsWith(NEW_RULE_PREFIX)) {
                currentRule = getRuleName(line.trim());
                inRule = currentRule != null;
                if (inRule) {
                    currentResult = results.get(currentRule);
                    if (currentResult == null) {
                        currentResult = new AptResult(currentRule);
                    }
                }
            } else if (inRule && !inExample && isExampleSeparator(line)) {
                inExample = true;
                inDescription = false;
                currentResult.description += "<pre>\n";
            } else if (inRule && !inExample && !inDescription && !inParameters && isValidDescriptionLine(line)) {
                inDescription = true;
                if (StringUtils.isNotBlank(line)) {
                    currentResult.description += "<p>" + line;
                }
            } else if (inRule && !inExample && inDescription && !inParameters
                    && !currentResult.description.endsWith("</pre>\n") && isValidDescriptionLine(line)) {
                if (isEndOfParagraph(currentResult, line)) {
                    currentResult.description += "</p>\n";
                } else {
                    currentResult.description += getParagraphLine(currentResult, line);
                }
            } else if (inRule && inExample && isExampleSeparator(line)) {
                inExample = false;
                inDescription = true;
                currentResult.description += "</pre>\n";
            } else if (inRule && inExample) {
                currentResult.description += fullLine + "\n";
            } else if (inRule && !inParameters && line.matches(PARAMETER_START_SEPARATOR)) {
                inDescription = false;
                inParameters = true;
                currentParameter = new RuleParameter();
                splits[0] = line.indexOf('*') + 1;
                splits[1] = line.indexOf('+', splits[0]) + 1;
                splits[2] = line.indexOf('+', splits[1]) + 1;
            } else if (inRule && inParameters && (line.matches(PARAMETER_CONTENT))) {
                String[] blocks = new String[3];
                blocks[0] = line.substring(splits[0], splits[1] - 1);
                blocks[1] = line.substring(splits[1], splits[2] - 1);
                blocks[2] = line.substring(splits[2], line.length() - 1);
                if (blocks.length == 3 && !isHeaderLine(blocks)) {
                    String key = blocks[0].trim();
                    String description = blocks[1].trim();
                    String defaultValue = blocks[2].trim();
                    if (StringUtils.isNotBlank(key)) {
                        currentParameter.key = currentParameter.key + key.replaceAll("(-)+", "");
                    }
                    if (StringUtils.isNotBlank(defaultValue) && !currentParameter.hasDefaultValue()) {
                        currentParameter.defaultValue = cleanDefaultValue(defaultValue);
                    }
                    if (StringUtils.isNotBlank(description)) {
                        currentParameter.description = currentParameter.description
                                + cleanDescription(description, true) + " ";
                    }
                }
            } else if (inRule && inParameters && isParameterSeparator(line)) {
                if (!currentParameter.isEmpty()) {
                    currentResult.parameters.add(currentParameter);
                }
                currentParameter = new RuleParameter();
            } else if (inRule && inParameters) {
                if (!currentParameter.isEmpty()) {
                    currentResult.parameters.add(currentParameter);
                }
                currentParameter = new RuleParameter();
                inParameters = false;
                inDescription = true;
            }
        }

        // last item
        if (inRule) {
            results.put(currentRule, currentResult);
        }

        return results;
    }

    private static boolean isExampleSeparator(String line) {
        return line.matches(EXAMPLE_SEPARATOR_1) || line.matches(EXAMPLE_SEPARATOR_2);
    }

    private static String getParagraphLine(AptResult currentResult, String line) {
        return (StringUtils.isNotBlank(line) && currentResult.description.endsWith("\n")
                || StringUtils.isBlank(currentResult.description) ? "<p>" : "") + cleanDescription(line, false)
                + " ";
    }

    private static boolean isEndOfParagraph(AptResult currentResult, String line) {
        return StringUtils.isBlank(line) && StringUtils.isNotBlank(currentResult.description)
                && !currentResult.description.endsWith("</p>\n");
    }

    private static boolean isValidDescriptionLine(String line) {
        return !startsWith(line, "<Since", "~~~", "<New", "** ", "[]", "*----", "+----", "|")
                && !isParameterSeparator(line);
    }

    private static boolean startsWith(String line, String... prefixes) {
        for (String prefix : prefixes) {
            if (line.startsWith(prefix)) {
                return true;
            }
        }
        return false;
    }

    private static boolean isParameterSeparator(String line) {
        return line.matches(PARAMETER_SEPARATOR) || line.matches(PARAMETER_START_SEPARATOR);
    }

    private static String cleanDescription(String description, boolean isForParameter) {
        String result = description;
        if (!isForParameter) {
            result = result.replaceAll("<<<", "<code>");
            result = result.replaceAll("<<", "<code>");
            result = result.replaceAll(">>>", "</code>");
            result = result.replaceAll(">>", "</code>");
        } else {
            result = result.replaceAll("<<<", "");
            result = result.replaceAll("<<", "");
            result = result.replaceAll(">>>", "");
            result = result.replaceAll(">>", "");
        }
        return result;
    }

    private static String cleanDefaultValue(String defaultValue) {
        String result = defaultValue.replaceAll("<<<", "");
        result = result.replaceAll("<<", "");
        result = result.replaceAll(">>>", "");
        result = result.replaceAll(">>", "");
        if (isBetween(result, "'", "'") || isBetween(result, "<", ">") || isBetween(result, "\"", "\"")
                || isBetween(result, "/", "/")) {
            result = result.substring(1, result.length() - 1);
        }
        return result;
    }

    private static boolean isBetween(String parameter, String prefix, String suffix) {
        return parameter.startsWith(prefix) && parameter.endsWith(suffix);
    }

    private static boolean isHeaderLine(String[] blocks) {
        return "<<Property>>".equalsIgnoreCase(blocks[0].trim());
    }

    private static String getRuleName(String line) {
        if (StringUtils.isBlank(line)) {
            return null;
        }
        String result = null;
        if (line.startsWith("* {")) {
            result = StringUtils.substringBetween(line, "* {", "} Rule").trim();
        } else {
            result = line.substring(2).trim();
        }
        if (result.endsWith("Rule")) {
            result = result.substring(0, result.length() - 4);
        }
        if (StringUtils.isAllLowerCase(result) || !StringUtils.isAlphanumeric(result)
                || "References".equals(result)) {
            // false positive
            return null;
        }
        return result;
    }

    private static void mergeParameters(Map<String, AptResult> results, Map<String, AptResult> parametersByFile) {
        for (String rule : parametersByFile.keySet()) {
            AptResult currentRuleResult = results.get(rule);
            if (currentRuleResult == null) {
                currentRuleResult = new AptResult(rule);
            }
            AptResult resultForRuleInFile = parametersByFile.get(rule);
            if (resultForRuleInFile.parameters != null) {
                for (RuleParameter parameter : resultForRuleInFile.getParameters()) {
                    if (!currentRuleResult.parameters.contains(parameter)) {
                        currentRuleResult.parameters.add(parameter);
                    }
                }
            }
            boolean alreadyHasExample = StringUtils.isNotBlank(currentRuleResult.description);
            boolean provideNewExample = StringUtils.isNotBlank(resultForRuleInFile.description);
            if (!alreadyHasExample && provideNewExample) {
                currentRuleResult.description = resultForRuleInFile.description;
            } else if (alreadyHasExample && provideNewExample) {
                System.out.println("CONFLICT RULE " + rule);
                System.out.println(currentRuleResult.description);
                System.out.println("WITH");
                System.out.println(resultForRuleInFile.description);
            }
            results.put(rule, currentRuleResult);
        }

    }
}